1
2
3
4
5
6
7 from collections import namedtuple
8 import math
9 from ctypes.wintypes import COLORREF
10 import re
11
12 -class RGB(namedtuple('RGB',('red','green','blue'))):
13 """Represents a color as an RGB (red green blue) value"""
14
15 @classmethod
17 """factory method to create an RGB from a COLORREF ctypes instance"""
18 if isinstance(c,COLORREF):
19 c=c.value
20 return cls(c&0xff,(c>>8)&0xff,(c>>16)&0xff)
21
22 _re_RGBFunctionString=re.compile(r'rgb\(\s*(\d+%?)\s*,\s*(\d+%?)\s*,\s*(\d+%?)\s*\)',re.I)
23 _re_RGBAFunctionString=re.compile(r'rgba\(\s*(\d+%?)\s*,\s*(\d+%?)\s*,\s*(\d+%?)\s*,\s*\d+(\.\d+)?\s*\)',re.I)
24
25 @staticmethod
27 val=int(round(int(s[:-1])*2.55)) if s.endswith('%') else int(s)
28 if val<0 or val>255:
29 raise ValueError("%s out of range"%val)
30 return val
31
32 @classmethod
34 """
35 Factory method to create an RGB instance from a css RGB string representation.
36 """
37 s=s.strip()
38
39 m=cls._re_RGBFunctionString.match(s) or cls._re_RGBAFunctionString.match(s)
40 if m:
41 r=cls._RGBStringValToInt(m.group(1))
42 g=cls._RGBStringValToInt(m.group(2))
43 b=cls._RGBStringValToInt(m.group(3))
44 return RGB(r,g,b)
45 if s.startswith('#'):
46 sLen=len(s)
47 try:
48 val=int(s[1:],16)
49 except ValueError:
50 val=None
51 if val is not None:
52
53 if sLen==7 or sLen==9:
54 r=(val>>16)&0xff
55 g=(val>>8)&0xff
56 b=val&0xff
57 return RGB(r,g,b)
58
59 if sLen==4 or sLen==5:
60 r=((val>>8)&0xf)+(((val>>8)&0xf)<<4)
61 g=((val>>4)&0xf)+(((val>>4)&0xf)<<4)
62 b=(val&0xf)+((val&0xf)<<4)
63 return RGB(r,g,b)
64 raise ValueError("invalid RGB string: %s"%s)
65
66 @property
68 foundName=RGBToNames.get(self,None)
69 if foundName:
70 return foundName
71 foundName=RGBToNamesCache.get(self,None)
72 if foundName:
73 return foundName
74 longestDistance=255.0
75 closestName=_("unknown color")
76 for possibleRGB,possibleName in RGBToNames.iteritems():
77 distance=math.sqrt(abs(self.red-possibleRGB.red)**2+abs(self.green-possibleRGB.green)**2+abs(self.blue-possibleRGB.blue)**2)
78 if distance<longestDistance:
79 longestDistance=distance
80 closestName=possibleName
81 RGBToNamesCache[self]=closestName
82 return closestName
83
84 RGBToNamesCache={}
85
86 RGBToNames={
87
88 RGB(0x00,0x00,0x00):_('black'),
89 RGB(0x00,0x80,0x00):_('green'),
90 RGB(0xc0,0xc0,0xc0):_('light grey'),
91 RGB(0x00,0xff,0x00):_('lime'),
92 RGB(0x80,0x80,0x80):_('grey'),
93 RGB(0x80,0x80,0x00):_('olive'),
94 RGB(0xff,0xff,0xff):_('white'),
95 RGB(0xff,0xff,0x00):_('yellow'),
96 RGB(0x80,0x00,0x00):_('dark red'),
97 RGB(0x00,0x00,0xa0):_('navy blue'),
98 RGB(0xff,0x00,0x00):_('red'),
99 RGB(0x00,0x00,0xff):_('blue'),
100 RGB(0x80,0x00,0x80):_('purple'),
101 RGB(0x00,0x80,0x80):_('teal'),
102 RGB(0xff,0x00,0xff):_('fuchsia'),
103 RGB(0x00,0xff,0xff):_('aqua'),
104
105 RGB(0xff,0xa5,0x00):_('orange'),
106 }
107