1
$\begingroup$

I'm trying to get the colors from the list of materials that contain an emission node and write them to an image file, pixel by pixel. Everything seemed to be working but the pixel colors that get written are much darker than the colors I'm getting from the default_value field in my emission nodes. For instance, after running the following script, the first brownish red color (#160100) ends up as (#020000) in the .png file.

import bpy

size = 16, 16
image = bpy.data.images.new("palette", width=size[0], height=size[1])

carray = []
cindex = 0

obj = bpy.context.active_object
for m in obj.material_slots:
    if m.name:
        #print(str(m.material.diffuse_color[:]))
        #carray.append(m.material.diffuse_color)
        if m.material.use_nodes:
            for n in m.material.node_tree.nodes:
                if n.type=='EMISSION':
                    color = n.inputs[0].default_value
                    carray.append(color)
        #else:
            #carray.append(m.material.diffuse_color)
            
                    
print(carray)

pixels = [None] * size[0] * size[1]
for y in range(size[1]):
    for x in range(size[0]):
        if cindex < len(carray):
            color = carray[cindex]
        else :
            color = [1.0,1.0,1.0,1.0]

        print(cindex)
        print(color)
        pixels[(abs(y-15) * size[0]) + x] = color#[r, g, b, a]
        cindex=cindex+1

# flatten list
pixels = [chan for px in pixels for chan in px]

# assign pixels
image.pixels = pixels

# write image
image.filepath_raw = "/temp/palette.png"
image.file_format = 'PNG'
image.save()
$\endgroup$

1 Answer 1

1
$\begingroup$

Credit to: @MarkyMarg2 https://twitter.com/MarkyMarg2/status/1290834859875692547 for solving this.

The colors need to be gamma corrected.

Each channel of RGB needs to be run through this formula:

if c < 0.0031308:
    srgb = 0.0 if c < 0.0 else c * 12.92
else:
    srgb = 1.055 * math.pow(c, 1.0 / 2.4) - 0.055

Here's a working example:

import bpy

size = 16, 16
image = bpy.data.images.new("palette", width=size[0], height=size[1])

carray = []
cindex = 0

def to_srgb(c):
    if c < 0.0031308:
        srgb = 0.0 if c < 0.0 else c * 12.92
    else:
        srgb = 1.055 * pow(c, 1.0 / 2.4) - 0.055

    return srgb

obj = bpy.context.active_object
for m in obj.material_slots:
    if m.name:
        #print(str(m.material.diffuse_color[:]))
        #carray.append(m.material.diffuse_color)
        if m.material.use_nodes:
            for n in m.material.node_tree.nodes:
                if n.type=='EMISSION':
                    color = n.inputs[0].default_value
                    carray.append(color)
        #else:
            #carray.append(m.material.diffuse_color)
            
                    
print(carray)

pixels = [None] * size[0] * size[1]
for y in range(size[1]):
    for x in range(size[0]):
        if cindex < len(carray):
            c = carray[cindex]
            color_fixed = [1.0,1.0,1.0,1.0]
            color_fixed[0] = to_srgb(c[0])
            color_fixed[1] = to_srgb(c[1])
            color_fixed[2] = to_srgb(c[2])
            color = color_fixed
        else :
            color = [1.0,1.0,1.0,1.0]

        print(cindex)
        print(color)
        pixels[(abs(y-15) * size[0]) + x] = color#[r, g, b, a]
        cindex=cindex+1

# flatten list
pixels = [chan for px in pixels for chan in px]

# assign pixels
image.pixels = pixels

# write image
image.filepath_raw = "/temp/palette.png"
image.file_format = 'PNG'
image.save()
$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .