Use external packages python 3dsmax

max
python
#1

I’m trying to work with image and python
I would like to use pillow or pygame , to do some stuff.
Even if I achieve to install with pip the packages, I have some dll error, due to what I read here probably.

Note: Python 2.7.12 is compiled with VC9.0, while 3ds Max 2019 (and its version of 3dsmaxpy.exe) is compiled with VC14.0. This means that you need to recompile CPython extension libraries for use with Python in 3ds Max with the more recent compiler.

I think this the reason why I cannot work with pillow or pygame

How di you face this problem?

#2

Did you know that the python multiprocessing library has a method that lets you run a different python executable? Because I sure didn’t until I started researching your problem.

https://docs.python.org/2/library/multiprocessing.html#multiprocessing.set_executable

I’m guessing you can use the multiprocessing interface to kick off a system python process to run your extension dependent code.

3 Likes
#3

One thing to watch out for is that the python process you kick off will inherit the current processes environment.
This could be good or bad depending on what you’re attempting to do.

On the maya side I’ve had better luck kicking off mayapy.exe with subprocess to call a script that then taps into multiprocessing

#4

Yeah, that environment thing could definitely come back to bite you… Though maybe just inserting some known paths into the beginning of sys.path could be enough, mixing imports from two different pythons sounds dangerous.

Using subprocess may be the way to go, but the data IO that feels like it would be a pain. Lots of reading and writing files. That’s why I looked at multiprocessing. It handles the data management for you via pickles and pipes. If you could set the multiprocessing environment, it would be a nice solution.

Hmmm… Sounds like that’s a module that could be written. Build a class that sets the executable and environment of a python process. Then have a call signature like
returnVal = externalClass(myFunc, args, kwargs)
that builds the process in the correct environment, and handles the pickle/pipe data transfer. I’m guessing most of the code could be copied directly from multiprocessing. I may play with that at some point

#5

This a great workaround usefull and I will investigate on it, but still I do not understand the real reason why my package are not working , and what shoudl I do , because clearly,reding the doc, for Autodesk it is pobbile to use external package with mayapy and 3dsmaxpy.

#6

Actually, it works just about exactly the way it is described in Autodesk reference.
You need to build some packages in order for it to work.

This command from the docs will download, build and install the Pillow:

pip install --no-cache-dir --no-binary pillow pillow

Since I don’t have zlib and jpeg environment set up it will fail for me without some additional options specified:

pip install --no-cache-dir --no-binary pillow --global-option="build_ext" --global-option="--disable-zlib" --global-option="--disable-jpeg" pillow

(It’s not particularly useful though since it cannot handle PNG, JPG or any format that requires zlib/jpeg, but you get the idea)

Tested with Max 2018/19.

#7

I’ll test again today .
I didn’t tought about the zlib/jpeg dependency.
Thanks for the hint

#8

To answer the original question (which I missed for some reason) on the Maya side of things where we face a similar problem of cpython incompatibilities, we just rebuild the extension from source.

In the case of pillow you’d need to ensure that you’ve got all of the dependencies built with the proper version of visual studio, and then finally build the extension. Its possible that these have already been built by someone out there and you just need to point the setup script at these pre-compiled versions.

#9

Hello, the Pillow package problem for 3Ds MAX 2018 is quite difficult for me.
I try to build the Pillow and failed.
I just want to use Pillow to combine some pictures into a .gif used in the 3Ds Max pyside ui.
As you said, I think I should use the system Python interpreter(Python2.7.15 on my PC) with Pillow 6.0.0 package installed. Use this interpreter to execute another script to generate the .gif picture. Am I right? Can you give some tips about how to accomplish multiprocessing 3Ds Max Python?
Thank you very much.
Yixiong Xu
2019.05.31

#10

Some python packages are less sensitive to the visual studio compile version than others. In the case of PIL, I would strongly recommend going with numpy + imageio + opencv2 instead. It is more complex (I would suggest writing a helper library to simplify how you interface with it) but way more capable and in my experience cross-compatible than PIL.

1 Like
#11

Are you needing to compile the gif at runtime?
If not then install a standalone python interpreter and use pip to install pillow and create your gif.
You could even do this at run time by calling the standalone python interpreter from max.
I used to do that before max had python.

1 Like
#13

Hello Munkybutt:
Thank you for your reply.
I just want to compile the .gif at run time. My purpose is to click a button and use the 3Ds Max to render a sequence of pictures and use these pictures to compile a .gif picture for Custom Plugin UI use in 3Ds Max.
I have accomplish the same purpose in Maya by use the imageio with other builded Pillow package, but for 3Ds Max, it’s too difficult for me.
I think the calling the standalone python interpreter from 3ds Max Python is a good solution, but I don’t know how to do, can you give me some tips?
Thank you very much.
Yixiong Xu
2019.06.02

#14

Assuming you have your standalone python interpreter installed on windows and accessible from the command line, you can use the subprocess module:
https://docs.python.org/2/library/subprocess.html#using-the-subprocess-module

import subprocess
subprocess.call(['python', 'myGifScript.py'])

In max, save your images to a folder.
myGifScript.py would contain the logic for compiling your gif from the images in said folder and saving the gif to disk.
Back in max you can watch for when the gif is saved to know when to load the gif into max python.
Do this with the first suggestion in this post:
http://timgolden.me.uk/python/win32_how_do_i/watch_directory_for_changes.html

The other suggestions require win32 which is even more difficult to compile as pillow.

1 Like
#15

OH,
It’s so kind of you.
Thank you very much.
It helps me a lot!!!

#16

No worries. Let me know how you get on.

#17

Hello Munkybutt,
In my code, I use subprocess.Popen(arg, shell = 1, stdout = subprocess.PIPE) instead of subprocess.Call() or subprocess.check_output().
I use subprocess.Popen.wait() to let the main process wait for the subprocess finishing and then Kill it.
Then I check the output value for further operation.
Because the output temp gif will soon be used by UI, if I want to re-write it, it will be failed because of the 3Ds Max is using it. So I use the shutil.copy2() to copy it. (It’s quite interesting for Maya, I don’t need to copy it, and re-writing works fine! Can anyone explain the reason?)
I let the 3Ds Max use the newer copied one and the script generate the source one.
Now, it works for me.
I think there should be some better solution, looking forward to your suggestions.
Yixiong Xu
2019.06.11

#18

How are you constructing your gif?
There is likely a way to release it once it is done being compiled.

#19

Hi Munkybutt,
I use the numpy+imageio packages, and I install their .wheel files to the system interpreter.(The wheel file can be download at PYPI. numpy is the latest version and imageio is 1.6)
As I said, I start a subprocess and use it to start the custom script with system interpreter.
Before run the custom script, I use Max Python API to generate a sequence of .png files. Their is a example script at Max Python API.
Then, in the custom script, I use imageio.minsave() to generate the target .gif file.
Back to the main plug_in, with the return value checked, I just copy the target file and use the copied .gif.
That’s all,
Thank you for your advices.
Yixiong Xu
2019.06.12