# how to convert rgb to hex? almost there. 1% error colors

I am trying to get a hex value out of material color. I find an reply here by @douripo: Get Hex triplet for color and real 256 RGB from diffuse Color using python

it successfully converts most of the colors to hex correctly. except a few. here is an example it does not convert right.

in blender, add a material to default cube and manually set its diffuse_color to hex 60590A (brown-ish yellow)

run below code in text editor, it would return 6059AA (purple-ish blue). could anyone check where went wrong? and hopefully a fix?

import bpy
import math

#code by : brecht - devtalk.blender.org
def to_hex(c):
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

return hex(max(min(int(srgb * 255 + 0.5), 255), 0))

def toHex(r,g,b):
rgb = [r,g,b]
result = ""
i=0
while i < 3:
val = str(to_hex(rgb[i]))
val = val[2:]
if len(val) == 1:
val += val
result+=val
i+=1
return result

ob = bpy.context.object
color_inferior = ob.active_material.diffuse_color

a = toHex(color_inferior[0],color_inferior[1],color_inferior[2])

print (a)


• 1% is a gross exaggeration: with just integers for colors it would be 16 / 256 cubed or less than one ten thousands of one percent of all possible colors.... , lol. Good spot. IIRC there is another answer re this converting both ways. ... actually prob less, 15 numerator since zero 00 would have worked as expected too. Aug 15, 2021 at 7:54
• That's counting colors where every RGB value is wrong, It's more like 17% where at least one RGB value is wrong. Aug 15, 2021 at 8:09
• @scurest No doubt it's OR ie 3 * 15 / 256 .. not AND never was good at stats Aug 15, 2021 at 8:47

The issue occurs when str(to_hex(rgb[i]))[2:] returns a length 1 value, which is the case for blue in example given "0xa".

        if len(val) == 1:
val += val


incorrectly turning it into "aa" instead of "0a". Using val = "0" + val will correct the issue. Another option, used below, is string formatting to convert an integer i into a zero padded length 2 hex string "%02x" % i

Here's a cleaned up version:

def linear_to_srgb8(c):
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

if srgb > 1: srgb = 1

return round(255*srgb)

def toHex(r, g, b):
return "%02x%02x%02x" % (
linear_to_srgb8(r),
linear_to_srgb8(g),
linear_to_srgb8(b),
)

• Fantastic !!! it works like a charm. thank you so very much for pointing it out and fixing it. Aug 15, 2021 at 18:40