import re from colorsys import hls_to_rgb from webcolors import html4_hex_to_names, hex_to_rgb, rgb_to_name, rgb_percent_to_hex, rgb_to_hex, css3_names_to_hex def closest_colour_rgb(requested_color): """ Function finds closes colour rgb """ min_colours = {} for key, name in html4_hex_to_names.items(): r_c, g_c, b_c = hex_to_rgb(key) rd = (r_c - requested_color[0]) ** 2 gd = (g_c - requested_color[1]) ** 2 bd = (b_c - requested_color[2]) ** 2 min_colours[(rd + gd + bd)] = name return min_colours[min(min_colours.keys())] def rgb2color_name(color): """ Transform rgb -> color name """ try: closest_name = actual_name = rgb_to_name(color, 'html4') except ValueError: closest_name = closest_colour_rgb(color) actual_name = None if actual_name: return actual_name else: return closest_name def hex2color_name(color): """ Transform hex -> color name """ try: color = hex_to_rgb(color) except ValueError: return '' try: closest_name = actual_name = rgb_to_name(color, 'html4') except ValueError: closest_name = closest_colour_rgb(color) actual_name = None if actual_name: return actual_name else: return closest_name def str2closest_html_color_name(s: str): """ Transform str -> closest color name """ if 'rgb' in s: rgb_str = 'rgba' if ('rgba' in s) else 'rgb' s = s.replace(rgb_str, '').replace('(', '').replace(')', '') try: rgb = [int(x) for x in s.split(',')[:3]] rgb = tuple(rgb) except ValueError: return '' if len(rgb) != 3: return '' name = rgb2color_name(rgb) return name elif '#' in s: if s in ['#996A95', '#D5C9D3', '#E9E2E8', '#70416F']: return 'purple' if s in ['#FFD472', '#F47B4D', '#FFFBEF', '#F47B4D']: return 'olive' if s in ['#B0DFD7', '#EFF8F6', '#5CC4B7']: return 'teal' name = hex2color_name(s) if (name == 'white') and (s.lower() not in ['#ffffff', '#fff']): name = 'gray' return name elif s in html4_hex_to_names.items(): return s else: return '' def rgba2rgb(r, g, b, alpha): """ Transform rgba -> rgb """ r_background, g_background, b_background = 255, 255, 255 r_new = int((1 - alpha) * r_background + alpha * r) g_new = int((1 - alpha) * g_background + alpha * g) b_new = int((1 - alpha) * b_background + alpha * b) return r_new, g_new, b_new def str2hex(s: str): """ Transform str -> hex """ if '#' in s and (len(s) <= 7): return s.lower() if ('rgb' in s) and ('%' in s): match = re.search(r'rgba*\(((\d+)%, *(\d+)%, *(\d+)%(, \d\.\d+)*)\)', s) if match: r, g, b = int(match.group(2)), int(match.group(3)), int(match.group(4)) return rgb_percent_to_hex((r, g, b)) if 'rgb' in s: match = re.search(r'rgba*\(((\d+), *(\d+), *(\d+), (\d\.\d+)*)\)', s) if match: r, g, b = int(match.group(2)), int(match.group(3)), int(match.group(4)) if match.group(5): alpha = float(match.group(5)) r, g, b = rgba2rgb(r, g, b, alpha) return rgb_to_hex((r, g, b)) if 'hsl' in s: # hsl(hue in {0,360}, saturation [0, 100%], lightness [0, 100%]) match = re.search(r'hsla*\(((\d+), *(\d+)%, *(\d+)%, (\d\.\d+)*)\)', s) if match: h, s, l = int(match.group(2)), int(match.group(3)), int(match.group(4)) h /= 360 s /= 10 l /= 100 rgb = tuple(hls_to_rgb(h, s, l)) if match.group(5): alpha = match.group(5) rgb = rgba2rgb(*rgb, alpha) return rgb_to_hex(rgb) if s.lower() in css3_names_to_hex: return css3_names_to_hex[s.lower()] return '' if __name__ == '__main__': colors = [ (75, 0, 130), (255, 0, 255), (139, 69, 19), (46, 139, 87), (221, 160, 221) ] hex_colors = [ '#96F', '#000', '#4C4C4C', '#A00', '#99F' ] for c in colors: n = rgb2color_name(c) print("Actual colour:", c, ", closest colour name:", n) for c in hex_colors: n = hex2color_name(c) print("Actual colour:", c, ", closest colour name:", n) print()