jamesbowman / openexrpython

OpenEXR bindings for Python
Other
94 stars 35 forks source link

Unable to write header field with string value #41

Open theNewFlesh opened 4 years ago

theNewFlesh commented 4 years ago

When I run this:

import Imath as imath
import numpy as np
import OpenEXR

ctype = imath.Channel(imath.PixelType(imath.PixelType.HALF))

target = '/tmp/test_exr.exr'
data = {}
chans = {}
channels = list('RGBA')
for c in channels:
    chan = c.upper()
    data[chan] = np.zeros((5, 10), dtype=np.float16).tobytes()
    chans[chan] = ctype

header = OpenEXR.Header(10, 5)
header['channels'] = chans
header['foo'] = 'bar'

# ALSO-FAIL-------------------------------
# header['foo'] = 'bar'.encode('ascii')
# header['foo'] = 'bar'.encode('utf-8')

# Segmentation fault
# header['foo'] = list('bar'.encode('utf-8'))
# header['foo'] = [bytes([x]) for x in list('bar')]
# ------------------------------------------

file_ = OpenEXR.OutputFile(target, header)
file_.writePixels(data)

I get this:

XXX - unknown attribute: foo

Inside of my pytest environment I get a segmentation fault. This was not the case a few months ago, when I last ran them.

I'm guessing the problem is that PyList_Check(val) returns false when it shouldn't. I looked at PyType_FastSubclass, which PyList_Check uses, inside /usr/include/python3.7m/object.h but it seems impenetrable.

jamesbowman commented 4 years ago

Does:

header['foo'] = b'bar'

work?

theNewFlesh commented 4 years ago

Yes, but I get None when I read it back in.

jamesbowman commented 4 years ago

and you're using Python 3, correct?

theNewFlesh commented 4 years ago

3.7

jamesbowman commented 4 years ago

OK, I have added test case test_header_bytes to exercise this path:

https://github.com/jamesbowman/openexrpython/blob/master/test-exr.py#L362-L391

Please can you run test_exr.py - maybe this will clear up why you're seeing None for these attributes?

Also added a case in the implementation's header parser to give a more helpful error message when encountering a Unicode string in a header. test_header_string confirms the Exception.

theNewFlesh commented 4 years ago

It passes, but others fail.

theNewFlesh commented 4 years ago

The none makes sense if the macro isn't loading.

theNewFlesh commented 4 years ago

I am running a docker env (Ubuntu 20.04) with blender inside of it, blender comes packaged with its own python3.7. I have install OpenEXR there. I run test.py using Blender's python, which is just a normal python plus Blender libraries.

I have 2 test scripts:

test.py

import Imath as imath
import numpy as np
import OpenEXR

ctype = imath.Channel(imath.PixelType(imath.PixelType.HALF))

target = '/tmp/test.exr'
data = {}
chans = {}
channels = list('RGBA')
for c in channels:
    chan = c.upper()
    data[chan] = np.zeros((5, 10), dtype=np.float16).tobytes()
    chans[chan] = ctype

header = OpenEXR.Header(10, 5)
header['channels'] = chans
header['foo'] = 'bar'.encode('utf-8')

# ALSO-FAIL-------------------------------
# header['foo'] = 'bar'.encode('ascii')
# header['foo'] = 'bar'.encode('utf-8')

# Segmentation fault
# header['foo'] = list('bar'.encode('utf-8'))
# header['foo'] = [bytes([x]) for x in list('bar')]
# ------------------------------------------

file_ = OpenEXR.OutputFile(target, header)
file_.writePixels(data)

and

result.py

import OpenEXR

target = '/tmp/test.exr'
h = OpenEXR.InputFile(target).header()
print(h['foo'])

I can't run them as one file because I get this:

OSError: Cannot read image file "/tmp/test_exr.exr". Early end of file: read 0 out of 4 requested bytes.

When I run:

rm -rf /tmp/test.exr; python3.7 test.py; python3.7 result.py

I get:

b'bar'

When I run this:

rm -rf /tmp/test.exr; /root/blender/blender --background  test.py; /root/blender/blender --background  result.py

I get:

None

Pretty sure this tells me that blender's python thinks INCLUDED_IMF_STRINGVECTOR_ATTRIBUTE_H is undefined. I have deliberately added stuff to my system path to fix this but to no avail. Not sure if I need to put the include/OpenEXR dir in my PYTHONPATH variable.

pip install OpenEXR doesn't include the C++ file reference by INCLUDED_IMF_STRINGVECTOR_ATTRIBUTE_H I'm guessing. but apt install libopenexr-dev probably puts it in place, so python3.7 can see it, but not blender's python.

theNewFlesh commented 4 years ago

I have tried dumping the OpenEXR C++ files and SOs many places and modifying my sys.path, but to no avail. Can you recommend something?

Or alternatively.... Is it possible to package OpenEXR with all its C/C++ dependencies, so that when one installs pip installs OpenEXR they get a fully functioning OpenEXR implementation? Having pip packaged pyOpenVDB, I realize C++ introduces a number of complexities to the process, not found with pure python, but the normal expectation of pip packages is complete installation and functionality.

meshula commented 4 years ago

In case it's useful, OpenTimelineIO has a setup.py that facilitates building the C++ portions as part of the pip install. You can see it in the root of the OpenTimelineIO repo.