pyembroidery/pyembroidery/EmbThread.py

426 wiersze
17 KiB
Python

def build_unique_palette(thread_palette, threadlist):
"""Turns a threadlist into a unique index list with the thread palette"""
chart = [None] * len(thread_palette) # Create a lookup chart.
for thread in set(
threadlist
): # for each unique color, move closest remaining thread to lookup chart.
index = thread.find_nearest_color_index(thread_palette)
if index is None:
break # No more threads remain in palette
thread_palette[index] = None # entries may not be reused.
chart[index] = thread # assign the given index to the lookup.
palette = []
for thread in threadlist: # for each thread, return the index.
palette.append(thread.find_nearest_color_index(chart))
return palette
def build_palette(thread_palette, threadlist):
palette = []
for thread in threadlist: # for each thread, return the index.
palette.append(thread.find_nearest_color_index(thread_palette))
return palette
def build_nonrepeat_palette(thread_palette, threadlist):
last_index = None
last_thread = None
palette = []
for thread in threadlist: # for each thread, return the index.
index = thread.find_nearest_color_index(thread_palette)
if last_index == index and last_thread != thread:
repeated_thread = thread_palette[index]
repeated_index = index
thread_palette[index] = None
index = thread.find_nearest_color_index(thread_palette)
# index will no longer be repeated.
thread_palette[repeated_index] = repeated_thread
palette.append(index)
last_index = index
last_thread = thread
return palette
def find_nearest_color_index(find_color, values):
if isinstance(find_color, EmbThread):
find_color = find_color.color
red = (find_color >> 16) & 0xFF
green = (find_color >> 8) & 0xFF
blue = find_color & 0xFF
closest_index = None
current_closest_value = float("inf")
for current_index, t in enumerate(values):
if t is None:
continue
dist = color_distance_red_mean(
red, green, blue, t.get_red(), t.get_green(), t.get_blue()
)
if dist <= current_closest_value: # <= choose second if they tie.
current_closest_value = dist
closest_index = current_index
return closest_index
def color_rgb(r, g, b):
return int(((r & 255) << 16) | ((g & 255) << 8) | (b & 255))
def color_hex(hex_string):
h = hex_string.lstrip("#")
size = len(h)
if size == 6 or size == 8:
return int(h[:6], 16)
elif size == 4 or size == 3:
return int(h[0] + h[0] + h[1] + h[1] + h[2] + h[2], 16)
def color_distance_red_mean(r1, g1, b1, r2, g2, b2):
red_mean = int(round((r1 + r2) / 2))
r = int(r1 - r2)
g = int(g1 - g2)
b = int(b1 - b2)
return (
(((512 + red_mean) * r * r) >> 8)
+ 4 * g * g
+ (((767 - red_mean) * b * b) >> 8)
)
# See the very good color distance paper:
# https://www.compuphase.com/cmetric.htm
class EmbThread:
def __init__(
self,
thread=None,
description=None,
catalog_number=None,
details=None,
brand=None,
chart=None,
weight=None,
):
self.color = 0x000000
self.description = description # type: str
self.catalog_number = catalog_number # type: str
self.details = details # type: str
self.brand = brand # type: str
self.chart = chart # type: str
self.weight = weight # type: str
# description, catalog_number, details, brand, chart, weight
if thread is not None:
self.set(thread)
def __repr__(self):
parts = list()
parts.append("thread='%s'" % self.hex_color())
if self.description is not None:
parts.append("description='%s'" % self.description)
if self.catalog_number is not None:
parts.append("catalog_number='%s'" % self.catalog_number)
if self.details is not None:
parts.append("details='%s'" % self.details)
if self.brand is not None:
parts.append("brand='%s'" % self.brand)
if self.chart is not None:
parts.append("chart='%s'" % self.chart)
if self.weight is not None:
parts.append("weight='%s'" % self.weight)
return "EmbThread(%s)" % ", ".join(parts)
def __ne__(self, other):
return not self.__eq__(other)
def __eq__(self, other):
if other is None:
return False
if isinstance(other, int):
return self.color & 0xFFFFFF == other & 0xFFFFFF
try:
if isinstance(other, basestring):
return (
self.color & 0xFFFFFF
== EmbThread.parse_string_color(other) & 0xFFFFFF
)
except NameError:
if isinstance(other, str):
return (
self.color & 0xFFFFFF
== EmbThread.parse_string_color(other) & 0xFFFFFF
)
if not isinstance(other, EmbThread):
return False
if self.color & 0xFFFFFF != other.color & 0xFFFFFF:
return False
if self.description != other.description:
return False
if self.catalog_number != other.catalog_number:
return False
if self.details != other.details:
return False
if self.brand != other.brand:
return False
if self.chart != other.chart:
return False
if self.weight != other.weight:
return False
return True
def __hash__(self):
return self.color & 0xFFFFFF
def __str__(self):
if self.description is None:
return "EmbThread %s" % self.hex_color()
else:
return "EmbThread %s %s" % (self.description, self.hex_color())
def set_color(self, r, g, b):
self.color = color_rgb(r, g, b)
def get_opaque_color(self):
return 0xFF000000 | self.color
def get_red(self):
red = self.color >> 16
return red & 0xFF
def get_green(self):
green = self.color >> 8
return green & 0xFF
def get_blue(self):
blue = self.color
return blue & 0xFF
def find_nearest_color_index(self, values):
return find_nearest_color_index(int(self.color), values)
def hex_color(self):
return "#%02x%02x%02x" % (self.get_red(), self.get_green(), self.get_blue())
def set_hex_color(self, hex_string):
self.color = color_hex(hex_string)
def set(self, thread):
if isinstance(thread, EmbThread):
self.color = thread.color
self.description = thread.description
self.catalog_number = thread.catalog_number
self.details = thread.details
self.brand = thread.brand
self.chart = thread.chart
self.weight = thread.weight
elif isinstance(thread, int):
self.color = thread
elif isinstance(thread, dict):
if "name" in thread:
self.description = thread["name"]
if "description" in thread:
self.description = thread["description"]
if "desc" in thread:
self.description = thread["desc"]
if "brand" in thread:
self.brand = thread["brand"]
if "manufacturer" in thread:
self.brand = thread["manufacturer"]
if "color" in thread or "rgb" in thread:
try:
color = thread["color"]
except KeyError:
color = thread["rgb"]
if isinstance(color, int):
self.color = color
elif isinstance(color, tuple) or isinstance(color, list):
self.color = (
(color[0] & 0xFF) << 16
| (color[1] & 0xFF) << 8
| (color[2] & 0xFF)
)
else:
try:
if isinstance(color, basestring):
self.color = self.parse_string_color(color)
except NameError:
if isinstance(color, str):
self.color = self.parse_string_color(color)
if "hex" in thread:
self.set_hex_color(thread["hex"])
if "id" in thread:
self.catalog_number = thread["id"]
if "catalog" in thread:
self.catalog_number = thread["catalog"]
else:
try:
if isinstance(thread, basestring):
self.color = self.parse_string_color(thread)
except NameError:
if isinstance(thread, str):
self.color = self.parse_string_color(thread)
try: # We might be using python 3.
if isinstance(thread, long):
self.color = int(thread)
except NameError:
pass
@staticmethod
def parse_string_color(color):
if color == "random":
import random
return random.randint(0, 0xFFFFFF)
if color[0:1] == "#":
return color_hex(color[1:])
color_dict = {
"aliceblue": color_rgb(240, 248, 255),
"antiquewhite": color_rgb(250, 235, 215),
"aqua": color_rgb(0, 255, 255),
"aquamarine": color_rgb(127, 255, 212),
"azure": color_rgb(240, 255, 255),
"beige": color_rgb(245, 245, 220),
"bisque": color_rgb(255, 228, 196),
"black": color_rgb(0, 0, 0),
"blanchedalmond": color_rgb(255, 235, 205),
"blue": color_rgb(0, 0, 255),
"blueviolet": color_rgb(138, 43, 226),
"brown": color_rgb(165, 42, 42),
"burlywood": color_rgb(222, 184, 135),
"cadetblue": color_rgb(95, 158, 160),
"chartreuse": color_rgb(127, 255, 0),
"chocolate": color_rgb(210, 105, 30),
"coral": color_rgb(255, 127, 80),
"cornflowerblue": color_rgb(100, 149, 237),
"cornsilk": color_rgb(255, 248, 220),
"crimson": color_rgb(220, 20, 60),
"cyan": color_rgb(0, 255, 255),
"darkblue": color_rgb(0, 0, 139),
"darkcyan": color_rgb(0, 139, 139),
"darkgoldenrod": color_rgb(184, 134, 11),
"darkgray": color_rgb(169, 169, 169),
"darkgreen": color_rgb(0, 100, 0),
"darkgrey": color_rgb(169, 169, 169),
"darkkhaki": color_rgb(189, 183, 107),
"darkmagenta": color_rgb(139, 0, 139),
"darkolivegreen": color_rgb(85, 107, 47),
"darkorange": color_rgb(255, 140, 0),
"darkorchid": color_rgb(153, 50, 204),
"darkred": color_rgb(139, 0, 0),
"darksalmon": color_rgb(233, 150, 122),
"darkseagreen": color_rgb(143, 188, 143),
"darkslateblue": color_rgb(72, 61, 139),
"darkslategray": color_rgb(47, 79, 79),
"darkslategrey": color_rgb(47, 79, 79),
"darkturquoise": color_rgb(0, 206, 209),
"darkviolet": color_rgb(148, 0, 211),
"deeppink": color_rgb(255, 20, 147),
"deepskyblue": color_rgb(0, 191, 255),
"dimgray": color_rgb(105, 105, 105),
"dimgrey": color_rgb(105, 105, 105),
"dodgerblue": color_rgb(30, 144, 255),
"firebrick": color_rgb(178, 34, 34),
"floralwhite": color_rgb(255, 250, 240),
"forestgreen": color_rgb(34, 139, 34),
"fuchsia": color_rgb(255, 0, 255),
"gainsboro": color_rgb(220, 220, 220),
"ghostwhite": color_rgb(248, 248, 255),
"gold": color_rgb(255, 215, 0),
"goldenrod": color_rgb(218, 165, 32),
"gray": color_rgb(128, 128, 128),
"grey": color_rgb(128, 128, 128),
"green": color_rgb(0, 128, 0),
"greenyellow": color_rgb(173, 255, 47),
"honeydew": color_rgb(240, 255, 240),
"hotpink": color_rgb(255, 105, 180),
"indianred": color_rgb(205, 92, 92),
"indigo": color_rgb(75, 0, 130),
"ivory": color_rgb(255, 255, 240),
"khaki": color_rgb(240, 230, 140),
"lavender": color_rgb(230, 230, 250),
"lavenderblush": color_rgb(255, 240, 245),
"lawngreen": color_rgb(124, 252, 0),
"lemonchiffon": color_rgb(255, 250, 205),
"lightblue": color_rgb(173, 216, 230),
"lightcoral": color_rgb(240, 128, 128),
"lightcyan": color_rgb(224, 255, 255),
"lightgoldenrodyellow": color_rgb(250, 250, 210),
"lightgray": color_rgb(211, 211, 211),
"lightgreen": color_rgb(144, 238, 144),
"lightgrey": color_rgb(211, 211, 211),
"lightpink": color_rgb(255, 182, 193),
"lightsalmon": color_rgb(255, 160, 122),
"lightseagreen": color_rgb(32, 178, 170),
"lightskyblue": color_rgb(135, 206, 250),
"lightslategray": color_rgb(119, 136, 153),
"lightslategrey": color_rgb(119, 136, 153),
"lightsteelblue": color_rgb(176, 196, 222),
"lightyellow": color_rgb(255, 255, 224),
"lime": color_rgb(0, 255, 0),
"limegreen": color_rgb(50, 205, 50),
"linen": color_rgb(250, 240, 230),
"magenta": color_rgb(255, 0, 255),
"maroon": color_rgb(128, 0, 0),
"mediumaquamarine": color_rgb(102, 205, 170),
"mediumblue": color_rgb(0, 0, 205),
"mediumorchid": color_rgb(186, 85, 211),
"mediumpurple": color_rgb(147, 112, 219),
"mediumseagreen": color_rgb(60, 179, 113),
"mediumslateblue": color_rgb(123, 104, 238),
"mediumspringgreen": color_rgb(0, 250, 154),
"mediumturquoise": color_rgb(72, 209, 204),
"mediumvioletred": color_rgb(199, 21, 133),
"midnightblue": color_rgb(25, 25, 112),
"mintcream": color_rgb(245, 255, 250),
"mistyrose": color_rgb(255, 228, 225),
"moccasin": color_rgb(255, 228, 181),
"navajowhite": color_rgb(255, 222, 173),
"navy": color_rgb(0, 0, 128),
"oldlace": color_rgb(253, 245, 230),
"olive": color_rgb(128, 128, 0),
"olivedrab": color_rgb(107, 142, 35),
"orange": color_rgb(255, 165, 0),
"orangered": color_rgb(255, 69, 0),
"orchid": color_rgb(218, 112, 214),
"palegoldenrod": color_rgb(238, 232, 170),
"palegreen": color_rgb(152, 251, 152),
"paleturquoise": color_rgb(175, 238, 238),
"palevioletred": color_rgb(219, 112, 147),
"papayawhip": color_rgb(255, 239, 213),
"peachpuff": color_rgb(255, 218, 185),
"peru": color_rgb(205, 133, 63),
"pink": color_rgb(255, 192, 203),
"plum": color_rgb(221, 160, 221),
"powderblue": color_rgb(176, 224, 230),
"purple": color_rgb(128, 0, 128),
"red": color_rgb(255, 0, 0),
"rosybrown": color_rgb(188, 143, 143),
"royalblue": color_rgb(65, 105, 225),
"saddlebrown": color_rgb(139, 69, 19),
"salmon": color_rgb(250, 128, 114),
"sandybrown": color_rgb(244, 164, 96),
"seagreen": color_rgb(46, 139, 87),
"seashell": color_rgb(255, 245, 238),
"sienna": color_rgb(160, 82, 45),
"silver": color_rgb(192, 192, 192),
"skyblue": color_rgb(135, 206, 235),
"slateblue": color_rgb(106, 90, 205),
"slategray": color_rgb(112, 128, 144),
"slategrey": color_rgb(112, 128, 144),
"snow": color_rgb(255, 250, 250),
"springgreen": color_rgb(0, 255, 127),
"steelblue": color_rgb(70, 130, 180),
"tan": color_rgb(210, 180, 140),
"teal": color_rgb(0, 128, 128),
"thistle": color_rgb(216, 191, 216),
"tomato": color_rgb(255, 99, 71),
"turquoise": color_rgb(64, 224, 208),
"violet": color_rgb(238, 130, 238),
"wheat": color_rgb(245, 222, 179),
"white": color_rgb(255, 255, 255),
"whitesmoke": color_rgb(245, 245, 245),
"yellow": color_rgb(255, 255, 0),
"yellowgreen": color_rgb(154, 205, 50),
}
return color_dict.get(color.lower(), 0x000000)
# return color or black.