Save bake image as 32 bit float?

I’m trying to implement 32 bit float as a feature for Principled Baker.
Right after baking the image properties says: “Image: size _ x _, RGB float
But the saved image is always just 8 bit. Reloading the image (bpy.ops.image.reload()) shows the image properties as: “Image: size _ x _, RGB byte

What am I missing?


The test scene is simple: just a cube with a material with an Emission node
This is the test code:

import bpy

mat_node_tree = bpy.context.active_object.material_slots['Material'].material.node_tree

image = bpy.data.images.new(name="test.tif", width=256, height=256, float_buffer=True)
image.filepath = "//test.tif"
image.file_format = 'TIFF'

image_node = mat_node_tree.nodes.new(type="ShaderNodeTexImage")
image_node.image = image
image_node.select = True
mat_node_tree.nodes.active = image_node

bpy.ops.object.bake(type='EMIT')

image.save()

should mentioning: I’m testing with Blender 2.80 beta

I always save out normal maps I bake in a 32bit full float EXR larger than my target size. Makes a fat file, but for the likes of a normal map, you kinda want it. I’m not sure tif supports it. I was under the impression other formats were limited to 16 bit.

1 Like

I forgot the mention that: Save the baked result manually gives at least 16 bit support with TIFF or PNG.
Maybe it’s that this only works with EXR.
But how to save as 16 bit?

In the code? Not sure, but I also know that most game engines will drop a 16 bit image to 8 bit on import. When you save out an image it looks like ImageFormatSettings.color_depth is the correct parameter to set.

https://docs.blender.org/api/master/bpy.types.ImageFormatSettings.html?highlight=imageformat#bpy.types.ImageFormatSettings

1 Like

Thank you for your help!

I got it half solved, but only for exr 32bit.
The problem was you have to set the file format (image.file_format) after baking.

Still having the problem how to save 16bit.

Well, on that same ref doc it looks like before saving you would:

  • Set ImageFormatSettings.file_format to TIFF/PNG
  • Set ImageFormatSettings.color_depth to 16
  • Then image.save()

That still does not work. Saving by hand works fine.

Here is the test code:

import bpy

mat_node_tree = bpy.context.active_object.material_slots['Material'].material.node_tree

img_name = "test.tif"
image = bpy.data.images.new(name=img_name, width=256, height=256, float_buffer=True)
image.filepath = "//"+img_name

image_node = mat_node_tree.nodes.new(type="ShaderNodeTexImage")
image_node.image = image
image_node.select = True
mat_node_tree.nodes.active = image_node

bpy.ops.object.bake(type='EMIT')

bpy.types.ImageFormatSettings.file_format = 'TIFF'
bpy.types.ImageFormatSettings.color_depth = '16'

image.save()

Well, what you need is an example that works, yes? I know TexTools works and a brief look in there suggests that they should be separate methods. One to define the image params, one to bake that calls that method for the image.

I already looked in the TexTools code. Surpise:

# image.save()

Saving is commented out in the code … :joy:

As far as I know, TexTools does not auto save images.

Ah. I see. try these:

def BAKE_EMIT(self, context)
    TMP_SAMPLES = bpy.context.scene.cycles.samples
    bpy.context.scene.cycles.samples = 1 
    bpy.ops.object.bake(type='EMIT')
    bpy.context.scene.cycles.samples = TMP_SAMPLES

I’m not sure TMP_SAMPLES is needed, but I wouldn’t want to have someone’s render sample settings changed in the scene without putting it back to whatever they had it set at. That’s just rude :wink:
I’d test it both ways and see.

and for the textures…

    bpy.ops.image.save_as()

https://docs.blender.org/api/master/bpy.ops.image.html?highlight=save#bpy.ops.image.save_as

Looks like image.save() is to save changes to an existing image, perhaps.

Thanks! Copy & Paste :stuck_out_tongue:
Till I put settings for samples in the add-on, you can set the samples in the render settings.


So, how do I use the operator on a certain image? Image objects don’t have .save_as() method.

I had to poke around in the console to see what I was missing:

import bpy

def BAKE_EMIT():
    TMP_SAMPLES = bpy.context.scene.cycles.samples
    bpy.context.scene.cycles.samples = 1
    bpy.ops.object.bake(type='EMIT')
    bpy.context.scene.cycles.samples = TMP_SAMPLES


mat_node_tree = bpy.context.active_object.material_slots['Material'].material.node_tree

img_name = "test.exr"
image = bpy.data.images.new(name=img_name, width=1024, height=1024, float_buffer=True)
image.filepath = "//"+img_name

image_node = mat_node_tree.nodes.new(type="ShaderNodeTexImage")
image_node.image = image
image_node.color_space = 'NONE'
image_node.select = True
mat_node_tree.nodes.active = image_node

BAKE_EMIT()

bpy.data.images[img_name].file_format = 'OPEN_EXR'

image.save()

Haven’t figured out how to control 8/16 bit yet, but there’s a 32 bit full float exr.

Edit: and here’s the problem: https://blender.stackexchange.com/questions/27317/saving-a-16-bit-png-using-script

So, you’d have to create a temporary scene and use render settings to do it.

1 Like

I got it now working with changing the bpy.context.scene.render.image_settings and saving with image.save_render(filepath).
I’ll implement this over the weekend and post simple code as a solution.

Thanks for your help!