NucleoSpec / lib /pythoms /colour.py
viviandlin
Initial release of NucleoSpec
33ba306
Raw
History Blame Contribute Delete
8.4 kB
"""
IGNORE:
takes an input string, tuple, or list and attempts to interpret it as a colour
new:
several methods were rewritten to be less restrictive
updated docstring
added cmyk support (both to and from)
added printdetails method for easy colour conversion
made it so hex input does not need a '#'
---2.1---
---2.2
IGNORE
"""
class Colour(object):
def __init__(self, c, rgb_scale=255, cmyk_scale=100):
"""
Takes an input colour string and stores several colour properties of that colour
**Parameters**
c: *string* or *tuple*
Input string (predefined colour or hex code) or R,G,B tuple.
rgb_scale: *integer*
The maximum value of the RGB scale for this object. Default is 255, implying
RGB values between 0-255.
cmyk_scale: *integer*
The maximum value of the CMYK scale. Currently unused
**Examples**
::
>>> col = Colour((89,89,89))
>>> col.print_details()
Colour (89, 89, 89)
RGB: 89, 89, 89
RGB (0-1): 0.349, 0.349, 0.349
CMYK: 0.0, 0.0, 0.0, 65.1
hex: #595959
>>> col.mpl # matplotlib RGB format (floats between 0 and 1)
(0.34901960784313724, 0.34901960784313724, 0.34901960784313724)
>>> col2 = Colour('#A8E5B0')
>>> col2.rgb
(168, 229, 176)
>>> col2.cmyk
(26.637554585152838, 0.0, 23.144104803493455, 10.196078431372547)
**Predefined Colours**
b: blue
r: red
g: olive green
p: purple
o: orange
a: aqua
k: black
d_: dark colour (ex. 'db' = dark blue)
l_: light colour (ex. 'lb' = light blue)
"""
self.c = c
self.rgb_scale = float(rgb_scale)
self.cmyk_scale = float(cmyk_scale)
self.ty = type(self.c)
if self.ty == str: # interpret as string
self.interpretstring(c)
elif self.ty == tuple or self.ty == list: # interpret as list or tuple
if len(self.c) == 3:
self.validatergb(self.c)
self.rgb = self.c
self.cmyk = self.rgb_to_cmyk(self.rgb)
elif len(self.c) == 4:
self.validatecmyk(self.c)
self.cmyk = self.c
self.rgb = self.cmyk_to_rgb(self.cmyk)
self.hex = self.rgb_to_hex(self.rgb)
self.mpl = self.mplcolour(self.rgb) # generate matplotlib colour tuple
self.rgb_to_others() # calculate other values
def __str__(self):
return 'Colour {}'.format(self.c)
def __repr__(self):
return '{}({})'.format(self.__class__.__name__, self.c)
def hex_to_rgb(self, string):
"""
converts hex colour to tuple
snagged from http://stackoverflow.com/questions/214359/converting-hex-color-to-rgb-and-vice-versa
"""
string = string.lstrip('#') # remove hash if present
lv = len(string)
if lv % 3 == 0:
out = []
for i in range(0, lv, lv // 3):
out.append(int(string[i:i + lv // 3], 16)) # append integer in base 16
return tuple(out)
# return tuple(int(string[i:i + lv // 3], 16) for i in range(0, lv, lv // 3)) #list-comprehension version
else:
raise ValueError('The provided colour string "%s" could not be interpreted as a colour.\n%s' % (
string, self.__class__.__doc__))
def cmyk_to_rgb(self, tup):
"""converts cmyk tuple to rgb"""
# set values and normalize
c, m, y, k = tup
c /= self.cmyk_scale
m /= self.cmyk_scale
y /= self.cmyk_scale
k /= self.cmyk_scale
# convert to RGB and scale
r = int(round(self.rgb_scale * (1.0 - c) * (1.0 - k), 0))
g = int(round(self.rgb_scale * (1.0 - m) * (1.0 - k), 0))
b = int(round(self.rgb_scale * (1.0 - y) * (1.0 - k), 0))
return r, g, b
def interpretstring(self, string):
"""interprets a string as a colour"""
colourdict = {
'b': (79, 129, 189),
'r': (192, 80, 77),
'g': (155, 187, 89),
'p': (128, 100, 162),
'a': (75, 172, 198),
'o': (247, 150, 70),
'lb': (149, 179, 215),
'lr': (217, 150, 148),
'lg': (195, 214, 155),
'lp': (179, 162, 199),
'lo': (147, 205, 221),
'la': (250, 192, 144),
'db': (54, 96, 146),
'dr': (99, 37, 35),
'dg': (79, 98, 40),
'dp': (64, 49, 82),
'do': (33, 89, 104),
'da': (152, 72, 7),
'k': (0, 0, 0),
}
if string in colourdict:
self.hex = self.rgb_to_hex(colourdict[string])
self.rgb = colourdict[string]
else:
self.rgb = self.hex_to_rgb(string)
self.hex = string
self.cmyk = self.rgb_to_cmyk(self.rgb)
def mplcolour(self, c):
"""converts 0-255 integers to 0-1 floats used by matplotlib"""
out = []
for val in c: # normalize output to 255
out.append(val / self.rgb_scale)
return tuple(out)
def printdetails(self):
"""prints the details of the object"""
import sys
sys.stdout.write('Colour %s\n' % str(self.c))
sys.stdout.write('RGB: %d, %d, %d\n' % self.rgb)
sys.stdout.write('RGB (0-1): %.3f, %.3f, %.3f\n' % self.mpl)
sys.stdout.write('CMYK: %.1f, %.1f, %.1f, %.1f\n' % self.cmyk)
# sys.stdout.write('HLS: %.3f, %.3f, %.3f\n' %self.hls)
# sys.stdout.write('HSV: %.3f, %.3f, %.3f\n' %self.hsv)
# sys.stdout.write('YIQ: %.3f, %.3f, %.3f\n' %self.yiq)
sys.stdout.write('hex: %s' % self.hex)
def rgb_to_cmyk(self, tup):
"""converts rgb tuple to cmyk"""
if sum(tup) == 0: # black
return 0, 0, 0, self.cmyk_scale
# set values and normalize
r, g, b = tup
r /= self.rgb_scale
g /= self.rgb_scale
b /= self.rgb_scale
# extract CMYK values
k = 1 - max(r, g, b)
c = (1 - r - k) / (1 - k)
m = (1 - g - k) / (1 - k)
y = (1 - b - k) / (1 - k)
# scale and return
return c * self.cmyk_scale, m * self.cmyk_scale, y * self.cmyk_scale, k * self.cmyk_scale
def rgb_to_hex(self, tup):
"""converts RGB tuple to hex code"""
return '#%02x%02x%02x' % tup
def rgb_to_others(self):
"""
converts RGB tuple to:
HLS (Hue Lightness Saturation)
HSV (Hue Saturation Value)
YIQ"""
import colorsys
r, g, b = [i / self.rgb_scale for i in self.rgb]
self.hls = colorsys.rgb_to_hls(r, g, b)
self.hsv = colorsys.rgb_to_hsv(r, g, b)
self.yiq = colorsys.rgb_to_yiq(r, g, b)
def validatecmyk(self, tup):
"""checks that values in a CMYK tuple are valid"""
for val in tup:
if type(val) != int and type(val) != float:
raise ValueError('One of the values in the CMYK colour tuple is not a number (%s).\n%s' % (
str(val), self.__class__.__doc__))
if val > self.cmyk_scale or val < 0:
raise ValueError(
'One of the values in the CMYK colour tuple (%s) is outside of the valid range (0-%d)\n%s' % (
str(val), self.cmyk_scale, self.__class__.__doc__))
def validatergb(self, tup):
"""checks that values in an RGB tuple are valid"""
for val in tup:
if type(val) != int:
raise ValueError(
'One of the values in the RGB colour tuple is not an integer ("%s").\nPlease correct the value.\n%s' % (
str(val), self.__class__.__doc__))
elif val > self.rgb_scale or val < 0:
raise ValueError(
'One of the values in the RGB colour tuple (%s) is outside of the valid RGB range of 0-%d.\n%s' % (
str(val), self.rgb_scale, self.__class__.__doc__))
if __name__ == '__main__':
col = Colour((89, 89, 89))
col.printdetails()