Communicating between Photoshop and Maya (Python)

Okay so I’ve finally started going into this and I’m really stuck at square one.
I’ve read both these blog posts below and I know Python good enough to start doing a project.

Problem is that Maya doesn’t find either of this modules. Trying to run the same code as in the examples above (from Maya) just gives me these error codes:

Error: No module named comtypes.client

Error: No module named win32com.client

What am I missing here?

comtypes download | SourceForge.net for comtypes. I think win32com is in Python for Windows Extensions - Browse Files at SourceForge.net

Oh, I expected them to be native to windows or something.
This means that all end-users of my future scripts are going to have to download these python modules too. Such a bummer :frowning:

Yep. Welcome to python tools distribution :confused:

There’s a slightly more complicated alternative that does not use comtypes.
You can write a .jsx script from Python then call “photoshop.exe <scriptname>”. When photoshop is already running it will just execute the script. Quixel’s dDo is using this technique.

[QUOTE=RobertKist;23433]There’s a slightly more complicated alternative that does not use comtypes.
You can write a .jsx script from Python then call “photoshop.exe <scriptname>”. When photoshop is already running it will just execute the script. Quixel’s dDo is using this technique.[/QUOTE]
That’s not a bad idea actually. I don’t mind learning a bit of javascript in order to make this stuff happen. So how do you tell Photoshop to run a script? I got this part:


import subprocess

photoshop = r"X:\Adobe\Adobe Photoshop CC (64 Bit)\Photoshop.exe"
texture = r"X:\Lolpath	est.psd"

subprocess.call((photoshop, texture))

Two other python questions that are somewhat related (instead of making a new thread):

  1. Does Python offer support for image manipulation (nativly) or do I need to download a third-party module for that?
    I was thinking that maybe some of the processing I want to do can be done directly by Python - before opening up the Photoshop application.

  2. Exactly how fast is Python when swapping colors of say… 16,7 million pixels? (4096 x 4096)
    Lets say that I want an algorithm that goes through all black (0 0 0) pixels in an image, then looks at it’s neighbors and then assigns a new value to the black pixel based on the colors of the neighbors and some other conditions. Would that easily become slow or am I underestimating the power of Python here?

You may actually have to use the alternative RobertKist mentioned anyways. With Maya 2013 and beyond I haven’t been able to successfully import the wincom32 module. It appears others have run into the same issue as well.

To run the script, you just append the script path to the photoshop path so X:\Adobe\Adobe Photoshop CC (64 Bit)\Photoshop.exe X:\Lolpath est.jsx. I used this method to talk back and forth from Max to Photoshop

Heres a nice read: Pete Hanshaw: Python Photoshop Automation without win32com- The Example

Also regarding distribution, you can convert to an exe.

@Crispy: Not sure if it was 2013 or 2014 but maybe someone just needs to re-compile with VS2010 as they changed that in one of them (cant remember which as we’re still on 2012 :P)

[QUOTE=haiddasalami;23439]To run the script, you just append the script path to the photoshop path so X:\Adobe\Adobe Photoshop CC (64 Bit)\Photoshop.exe X:\Lolpath est.jsx. I used this method to talk back and forth from Max to Photoshop

Heres a nice read: Pete Hanshaw: Python Photoshop Automation without win32com- The Example

Also regarding distribution, you can convert to an exe.

@Crispy: Not sure if it was 2013 or 2014 but maybe someone just needs to re-compile with VS2010 as they changed that in one of them (cant remember which as we’re still on 2012 :P)[/QUOTE]

I don’t follow.


import subprocess

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

subprocess.call((photoshop, texture))

Gives me an error saying that the system cannot find the file specified (because both paths are in the same string).
Is the script path supposed to go into “call” as a separate argument or something?
Also, I use javascript or VBscript instead of extendScript (jsx), yes?

Anyway I found Peter’s blog yesterday: lots of good stuff there!! I’m gonna go through as much of it as I can :slight_smile:

I need to get my pslib up to snuff, its pure python and you can subscribe to events.

Anyhow, use javascript and save it as .jsx. Use the ExtendScript Toolkit to help debug your scripts in pS

[QUOTE=TheMaxx;23457]I need to get my pslib up to snuff, its pure python and you can subscribe to events.

Anyhow, use javascript and save it as .jsx. Use the ExtendScript Toolkit to help debug your scripts in pS[/QUOTE]

It doesn’t matter what language or extension it - the above code I wrote in the post before this one doesn’t work. Maya doesn’t even start Photoshop of I append the script path to the end of the photoshop path like that.

And where can I subscribe?

I’m thinking you need to quote the path to PS as it contains spaces:


import subprocess

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

subprocess.call((photoshop, texture))

[QUOTE=TheMaxx;23463]I’m thinking you need to quote the path to PS as it contains spaces:


import subprocess

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

subprocess.call((photoshop, texture))

[/QUOTE]

Well now something happens, but another error ofc:

WindowsError: [Error 5] Access is denied

Seems to have to do with the syntax of that string

[QUOTE=Nightshade;23455]
Is the script path supposed to go into “call” as a separate argument or something?
[/QUOTE]

Yes, the script path should go into the “call” as well, each argument should be passed separately.


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, script, texture))

[QUOTE=akira;23468]Yes, the script path should go into the “call” as well, each argument should be passed separately.


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, script, texture))

[/QUOTE]

Yes that made it work on the Python side of things.
But now another issue came up - and it’s always like this: solve one problem, another appears on the next step right after. 0% actual developing, 100% trying to sort out bullshit. That’s what it has been like so far :frowning:

Now what I have is Photoshop complaining.

Error 8800: General Photoshop error occured. This functionality may not be available in this version of Photoshop.

This error is just that - bullshit. Because when I execute the script from inside Photoshop, it works as it should.
The script I’ve been testing is this one: http://blog.xshock.de/content/resources/scripts/xshock_selectlayerbelow.zip

It’s written in javascript, it works exactly as it should, it’s just Photoshop bitching - or subprocess isn’t activating the script properly.
I know this because even when I try to call on any NATIVE Photoshop script, I get an error!! Trying to execute an extendscript (jsx) I get this instead:

IOError: General Photoshop error occured. This functionality may not be available in this version of Photoshop.

So I thought that maybe subprocess is trying to execute the script before the workfile is open, so I opened up photoshop and the workfile and then ran the Python code:
Same problem. Running the script via Python triggers that weird error - running the script inside Photoshop manually works as a charm.

running that script with:


>>> import subprocess
>>> subprocess.Popen(r'"C:\Program Files\Adobe\Adobe Photoshop CS6 (64 Bit)\Photoshop.exe" c:	mp\xshock_SelectLayerBelow.jsx')

Works as expected

[QUOTE=TheMaxx;23482]running that script with:


>>> import subprocess
>>> subprocess.Popen(r'"C:\Program Files\Adobe\Adobe Photoshop CS6 (64 Bit)\Photoshop.exe" c:	mp\xshock_SelectLayerBelow.jsx')

Works as expected[/QUOTE]

Aaaah, now I know why it works for you and why it didn’t for me.
In your example there, you have omitted a path to a workfile, which got me thinking.
So I switched the order of the arguments into: photoshop, texture and then the script. NO ERRORS. (previously I had the script argument on second place, and the workfile on the second.)

Now I got another issue though:
The script is executed prematurely - before the workfile has been fully loaded in Photoshop. I get this both when Photoshop isn’t open, and when it is open - but not the workfile.
If Photoshop AND the workfile is open, then everything behaves as expected. This also explains my weird problems:
In that case, the first argument runs (opens Photoshop), and then subprocess gets a green light to run the second argument (script) - but does this prematurely before everything has been started up by Photoshop. The result is that Photoshop has no way of dealing with those scripts, throwing a general error at the user.

I guess this could easily be sorted out just by splitting that command and not try and run everything at once. Opening Photoshop and the workfile in one go is just fine - but the script has to be executed after the workfile has been -fully- loaded in Photoshop. :confused:

you could put the open call in the script. Actually, can you even pass arguments to the script or does it just run as-is? If not, just stick it in a while loop until app.activeDocument is not undefined.

[QUOTE=TheMaxx;23484]you could put the open call in the script. Actually, can you even pass arguments to the script or does it just run as-is? If not, just stick it in a while loop until app.activeDocument is not undefined.[/QUOTE]
Regarding passing external arguments to a javascript: it seems possible, but not fool proof. I found this: http://cjihrig.com/blog/passing-arguments-to-external-javascript-files/

Anyway I went with your last idea, so now I have:


// If no documents are open... (ie: Photoshop and the workfile is being started by the Python code)
if (app.documents == undefined) 
{
	// ...keep running the layer order script until the workfile is fully open
	while (app.documents == undefined)
	{
		// the script
	}
}
// Else if we already have a document open, just run the script once
else
{
	// the script
}

So far it’s working as it should!
I’m just worried about thing: Isn’t there a possiblity that the document is finished loading -during- the script execution - so that when the while-loop checks the condition again it finds out that “hey, the doc is loaded, no reason to run this code again”, resulting in the script never being fully executed on the open-document?

I would just use comtypes, it has a mit liscense so pretty flexible, and can be distrbuted with your script.

I was able to distribute it easily with one of my Maya plugins by using the maya module system.

comtypes is just easier since you can write in python code that runs directly in Photoshop.