2
$\begingroup$

How can I specify the file type and color depth when generating and packing an image with Python?

I'm trying to generate an image with full 32-bit float color depth and pack it into my blend file but I keep getting it revert back to 8-bits per channel.

I'm creating the image using the following python code :

import bpy

width = 800
height = 400

image = bpy.data.images.new("testimagepacked", width=width, height=height,float_buffer=True)

pixels = [None] * width * height

for x in range(0,width):
    for y in range(0,height):
        pixels[(y*width)+x] = [float(x)/width,float(y)/height,-y+x,1.0]

pixels = [chan for px in pixels for chan in px]
image.pixels = pixels
image.update()

This successfully creates the image and dragging the mouse across it in the UV/Image Editor shows that the pixels are correctly stored as floats (with the Blue channel ranging way beyond the usual 0.0, 1.0 limits and green and red not being rounded to 1/256ths).

example image

If I manually select Image/Save As Image and specify the format as OpenEXR, RGBA, Float(full) to save if as a file and then select Image/Pack then the image is packed into the blend file retaining its full 32-bit precision.

save as format

This shows that it's possible to pack the image in 32-bit precision.

I have tried to replicate these actions in Python but am unable to save the image as 32-bit float - I can't figure out how to specify the image file format.

The nearest I've got is to save the image as OpenEXR but, apparently, not in 32-bit float for the image loses its precision when it's packed using this :

image.file_format = 'OPEN_EXR'
image.filepath='//created image.exr'

image.save()
image.pack(as_png=False) # I expected this to pack as float rather than PNG but this doesn't seem to work
image.use_fake_user = True

How can I specify the Image Format Settings when saving the image from Python? Even better would be to be able to directly pack the image (as 32-bit float) without having to save it to disk at all, but I don't think this is possible.

$\endgroup$
  • 2
    $\begingroup$ Yep, seems not possible at the moment... the image needs to be saved before :/ Alternatively you could use python's tempfile library docs.python.org/3.6/library/tempfile.html (just an idea). $\endgroup$ – p2or Mar 7 '17 at 7:48
  • 1
    $\begingroup$ @poor Thanks - that sounds useful for generating a temporary filename - I'll look into that. $\endgroup$ – Rich Sedman Mar 7 '17 at 9:10
5
$\begingroup$

It would seem that to control the image format that gets packed into a blend file, you will need to save the image to disk and then re-open it.

To get control of the file format an image is saved to disk with, you can use save_render(). The render settings from the scene parameter holds the ImageFormatSettings which allow you to adjust the settings. If you don't want to use the render settings from the current scene you can create a new one just for this.

scn = bpy.data.scenes.new('img_settings')
scn.render.image_settings.file_format = 'OPEN_EXR_MULTILAYER'
scn.render.image_settings.color_mode = 'RGBA'
scn.render.image_settings.color_depth = '32'
img_path = bpy.path.abspath('//')
img_file = image.name+'.exr'
image.save_render(img_path+img_file, scene=scn)
bpy.data.scenes.remove(scn, do_unlink=True)

But this still leaves you with an edited image that doesn't respond to pack(). To get around this, remove the image block and open it from the file.

bpy.data.images.remove(image)
bpy.ops.image.open(filepath=img_path+img_file)
image = bpy.data.images[img_file]
image.pack()
os.remove(img_path+img_file)
$\endgroup$
  • $\begingroup$ Thanks! That looks like exactly what I need. I'll give it try. $\endgroup$ – Rich Sedman Mar 7 '17 at 9:48
  • 1
    $\begingroup$ Thanks very much for this - I've made two minor edits (one to use abspath('//') as '//' wasn't being correctly expanded and the other to include 'do_unlink=True' when removing the scene as it was failing due to a user still being present). This is working perfectly. Thanks again :-) $\endgroup$ – Rich Sedman Mar 8 '17 at 14:21
  • $\begingroup$ For info, discovered that the do_unlink is only valid (and required) in Blender version 2.78 and above. It was introduced to make the 'remove' behaviour more consistent between data types. $\endgroup$ – Rich Sedman Mar 8 '17 at 18:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.