From 290dc7bc1c39a243fd48a27c42716e2d9e752fa9 Mon Sep 17 00:00:00 2001 From: Joshua Dong Date: Fri, 22 Jan 2016 01:45:12 -0600 Subject: [PATCH 1/4] new: implement hsv --- colour.py | 106 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 101 insertions(+), 5 deletions(-) diff --git a/colour.py b/colour.py index 84500eb..96f540d 100644 --- a/colour.py +++ b/colour.py @@ -9,6 +9,9 @@ Formats ------- +HSV: + 3-uple of Hue, Saturation, Value all between 0.0 and 1.0 + HSL: 3-uple of Hue, Saturation, Lightness all between 0.0 and 1.0 @@ -465,6 +468,90 @@ def rgb2hsl(rgb): return (h, s, l) +def hsv2rgb(hsv): + """Convert HSV representation towards RGB + + :param h: Hue, position around the chromatic circle (h=1 equiv h=0) + :param s: Saturation, color saturation (0=full gray, 1=full color) + :param v: Value, brightness value(0=full black, 1=full brightness) + :rtype: 3-uple for RGB values in float between 0 and 1 + + Hue, Saturation, and Value are floats between 0 and 1 + + Note that Hue can be set to any value but as it is a rotation + around the chromatic circle, any value above 1 or below 0 can + be expressed by a value between 0 and 1 (Note that h=0 is equiv + to h=1). + + This algorithm came from: + http://www.easyrgb.com/index.php?X=MATH&H=21#text21 + + Here are some examples of HSV to RGB convertion: + + >>> from colour import hsv2rgb + + TODO: finish examples + + >>> hsv2rgb((1.0, 1.0, 1.0)) # doctest: +ELLIPSIS + (..., 0.0, 1.0) + >>> hsv2rgb((0.5, 0.5, 0.5)) # doctest: +ELLIPSIS + (..., 0.0, 0.5) + >>> hsv2rgb((0.0, 0.0, 0.0)) # doctest: +ELLIPSIS + (..., 0.0, 0.0) + + If only one color is different from the others, it defines the + direct Hue: + + >>> hsv2rgb((0.5, 0.5, 1.0)) # doctest: +ELLIPSIS + (0.66..., 1.0, 0.75) + >>> hsv2rgb((0.2, 0.1, 0.1)) # doctest: +ELLIPSIS + (0.0, 0.33..., 0.15...) + + Having only one value set, you can check that: + + >>> hsv2rgb((1.0, 0.0, 0.0)) + (0.0, 1.0, 0.5) + >>> hsv2rgb((0.0, 1.0, 0.0)) # doctest: +ELLIPSIS + (0.33..., 1.0, 0.5) + >>> hsv2rgb((0.0, 0.0, 1.0)) # doctest: +ELLIPSIS + (0.66..., 1.0, 0.5) + + Of course: + >>> hsv2rgb((0.0, 2.0, 0.5)) # doctest: +ELLIPSIS + Traceback (most recent call last): + ... + ValueError: Green must be between 0 and 1. You provided 2.0. + + And: + >>> hsv2rgb((0.0, 0.0, 1.5)) # doctest: +ELLIPSIS + Traceback (most recent call last): + ... + ValueError: Blue must be between 0 and 1. You provided 1.5. + + """ + h, s, v = [float(v) for v in hsl] + + #TODO: implement this + if not (0.0 - FLOAT_ERROR <= s <= 1.0 + FLOAT_ERROR): + raise ValueError("Saturation must be between 0 and 1.") + if not (0.0 - FLOAT_ERROR <= l <= 1.0 + FLOAT_ERROR): + raise ValueError("Lightness must be between 0 and 1.") + + if s == 0: + return l, l, l + + if l < 0.5: + v2 = l * (1.0 + s) + else: + v2 = (l + s) - (s * l) + + v1 = 2.0 * l - v2 + + r = _hue2rgb(v1, v2, h + (1.0 / 3)) + g = _hue2rgb(v1, v2, h) + b = _hue2rgb(v1, v2, h - (1.0 / 3)) + + def _hue2rgb(v1, v2, vH): """Private helper function (Do not call directly) @@ -788,7 +875,7 @@ class Color(object): """Abstraction of a color object Color object keeps information of a color. It can input/output to different - format (HSL, RGB, HEX, WEB) and their partial representation. + format (HSV, HSL, RGB, HEX, WEB) and their partial representation. >>> from colour import Color, HSL @@ -814,6 +901,8 @@ class Color(object): >>> b.rgb (0.0, 0.0, 1.0) + >>> b.hsv # doctest: +ELLIPSIS + (0.66..., 1.0, 1.0) >>> b.hsl # doctest: +ELLIPSIS (0.66..., 1.0, 0.5) >>> b.hex @@ -863,8 +952,10 @@ class Color(object): >>> c.saturation = 0.0 - >>> c.hsl # doctest: +ELLIPSIS + >>> c.hsv # doctest: +ELLIPSIS (..., 0.0, 0.5) + >>> c.hsl # doctest: +ELLIPSIS + (..., 0.5, 0.0) >>> c.rgb (0.5, 0.5, 0.5) >>> c.hex @@ -872,6 +963,10 @@ class Color(object): >>> c + >>> c.value = 0.5 + >>> c + + >>> c.luminance = 0.0 >>> c @@ -904,10 +999,8 @@ class Color(object): ... AttributeError: 'lightness' not found - TODO: could add HSV, CMYK, YUV conversion. + TODO: could add CMYK, YUV conversion. -# >>> b.hsv -# >>> b.value # >>> b.cyan # >>> b.magenta # >>> b.yellow @@ -1032,6 +1125,9 @@ def get_web(self): ## Set ## + def set_hsv(self, value): + self._hsl = hsv2hsl(value) + def set_hsl(self, value): self._hsl = list(value) From 9fe1f50130d4f6790a97c78f6df5bd27a36f7dd3 Mon Sep 17 00:00:00 2001 From: Joshua Dong Date: Fri, 22 Jan 2016 12:33:15 -0600 Subject: [PATCH 2/4] e --- colour.py | 384 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 255 insertions(+), 129 deletions(-) diff --git a/colour.py b/colour.py index 96f540d..81c8b34 100644 --- a/colour.py +++ b/colour.py @@ -204,16 +204,39 @@ SHORT_HEX_COLOR = re.compile(r'^#[0-9a-fA-F]{3}$') -class C_HSL: +class C_HSV: + """HSV colors container + + Provides a quick color access. + + >>> from colour import HSV + + >>> HSV.WHITE + (0.0, 0.0, 1.0) + >>> HSV.BLUE + (0.0, 0.0, 1.0) # TODO: filli this in + + >>> HSV.DONOTEXISTS # doctest: +ELLIPSIS + Traceback (most recent call last): + ... + AttributeError: ... has no attribute 'DONOTEXISTS' + + """ def __getattr__(self, value): label = value.lower() if label in COLOR_NAME_TO_RGB: - return rgb2hsl(tuple(v / 255. for v in COLOR_NAME_TO_RGB[label])) + return rgb2hsv(tuple(v / 255. for v in COLOR_NAME_TO_RGB[label])) raise AttributeError("%s instance has no attribute %r" % (self.__class__, value)) -HSL = C_HSL() +class C_HSL: + + def __getattr__(self, value): + label = value.lower() + if label in COLOR_NAME_TO_RGB: + return rgb2hsl(tuple(v / 255. for v in COLOR_NAME_TO_RGB[label])) + raise AttributeError("%s instance has no attribute %r" % (self.__class__, value)) class C_RGB: @@ -261,6 +284,9 @@ class C_HEX: def __getattr__(self, value): return rgb2hex(getattr(RGB, value)) + +HSV = C_HSV() +HSL = C_HSL() RGB = C_RGB() HEX = C_HEX() @@ -269,102 +295,104 @@ def __getattr__(self, value): ## Convertion function ## -def hsl2rgb(hsl): - """Convert HSL representation towards RGB +def rgb2hsv(rgb): + """Convert RGB representations to HSV - :param h: Hue, position around the chromatic circle (h=1 equiv h=0) - :param s: Saturation, color saturation (0=full gray, 1=full color) - :param l: Ligthness, Overhaul lightness (0=full black, 1=full white) - :rtype: 3-uple for RGB values in float between 0 and 1 - - Hue, Saturation, Range from Lightness is a float between 0 and 1 - - Note that Hue can be set to any value but as it is a rotation - around the chromatic circle, any value above 1 or below 0 can - be expressed by a value between 0 and 1 (Note that h=0 is equiv - to h=1). + :param r: Red amount (float between 0 and 1) + :param g: Green amount (float between 0 and 1) + :param b: Blue amount (float between 0 and 1) + :rtype: 3-uple for HSV values in float between 0 and 1 This algorithm came from: - http://www.easyrgb.com/index.php?X=MATH&H=19#text19 + http://www.easyrgb.com/index.php?X=MATH&H=20#text20 - Here are some quick notion of HSL to RGB convertion: + Here are some quick notion of RGB to HSV convertion: - >>> from colour import hsl2rgb - - With a lightness put at 0, RGB is always rgbblack + >>> from colour import rgb2hsv - >>> hsl2rgb((0.0, 0.0, 0.0)) - (0.0, 0.0, 0.0) - >>> hsl2rgb((0.5, 0.0, 0.0)) - (0.0, 0.0, 0.0) - >>> hsl2rgb((0.5, 0.5, 0.0)) - (0.0, 0.0, 0.0) + Note that if red amount is equal to green and blue, then you + should have a gray value (from black to white). - Same for lightness put at 1, RGB is always rgbwhite - >>> hsl2rgb((0.0, 0.0, 1.0)) - (1.0, 1.0, 1.0) - >>> hsl2rgb((0.5, 0.0, 1.0)) - (1.0, 1.0, 1.0) - >>> hsl2rgb((0.5, 0.5, 1.0)) - (1.0, 1.0, 1.0) + >>> rgb2hsv((1.0, 1.0, 1.0)) # doctest: +ELLIPSIS + (..., 0.0, 1.0) #TODO: fill in + >>> rgb2hsv((0.5, 0.5, 0.5)) # doctest: +ELLIPSIS + (..., 0.0, 0.5) #TODO: fill in + >>> rgb2hsv((0.0, 0.0, 0.0)) # doctest: +ELLIPSIS + (..., 0.0, 0.0) #TODO: fill in - With saturation put at 0, the RGB should be equal to Lightness: + If only one color is different from the others, it defines the + direct Hue: - >>> hsl2rgb((0.0, 0.0, 0.25)) - (0.25, 0.25, 0.25) - >>> hsl2rgb((0.5, 0.0, 0.5)) - (0.5, 0.5, 0.5) - >>> hsl2rgb((0.5, 0.0, 0.75)) - (0.75, 0.75, 0.75) + >>> rgb2hsv((0.5, 0.5, 1.0)) # doctest: +ELLIPSIS + (0.66..., 1.0, 0.75) #TODO: fill in + >>> rgb2hsv((0.2, 0.1, 0.1)) # doctest: +ELLIPSIS + (0.0, 0.33..., 0.15...) #TODO: fill in - With saturation put at 1, and lightness put to 0.5, we can find - normal full red, green, blue colors: + Having only one value set, you can check that: - >>> hsl2rgb((0 , 1.0, 0.5)) - (1.0, 0.0, 0.0) - >>> hsl2rgb((1 , 1.0, 0.5)) - (1.0, 0.0, 0.0) - >>> hsl2rgb((1.0/3 , 1.0, 0.5)) - (0.0, 1.0, 0.0) - >>> hsl2rgb((2.0/3 , 1.0, 0.5)) - (0.0, 0.0, 1.0) + >>> rgb2hsv((1.0, 0.0, 0.0)) + (0.0, 1.0, 0.5) #TODO: fill in + >>> rgb2hsv((0.0, 1.0, 0.0)) # doctest: +ELLIPSIS + (0.33..., 1.0, 0.5) #TODO: fill in + >>> rgb2hsv((0.0, 0.0, 1.0)) # doctest: +ELLIPSIS + (0.66..., 1.0, 0.5) #TODO: fill in - Of course: - >>> hsl2rgb((0.0, 2.0, 0.5)) # doctest: +ELLIPSIS + Bad input throws an exception: + >>> rgb2hsv((0.0, 2.0, 0.5)) # doctest: +ELLIPSIS Traceback (most recent call last): ... - ValueError: Saturation must be between 0 and 1. - - And: - >>> hsl2rgb((0.0, 0.0, 1.5)) # doctest: +ELLIPSIS + ValueError: Green must be between 0 and 1. You provided 2.0. + >>> rgb2hsv((0.0, 0.0, 1.5)) # doctest: +ELLIPSIS Traceback (most recent call last): ... - ValueError: Lightness must be between 0 and 1. + ValueError: Blue must be between 0 and 1. You provided 1.5. """ - h, s, l = [float(v) for v in hsl] + # TODO: implement + r, g, b = [float(v) for v in rgb] - if not (0.0 - FLOAT_ERROR <= s <= 1.0 + FLOAT_ERROR): - raise ValueError("Saturation must be between 0 and 1.") - if not (0.0 - FLOAT_ERROR <= l <= 1.0 + FLOAT_ERROR): - raise ValueError("Lightness must be between 0 and 1.") + for name, v in {'Red': r, 'Green': g, 'Blue': b}.items(): + if not (0 - FLOAT_ERROR <= v <= 1 + FLOAT_ERROR): + raise ValueError("%s must be between 0 and 1. You provided %r." + % (name, v)) - if s == 0: - return l, l, l + vmin = min(r, g, b) ## Min. value of RGB + vmax = max(r, g, b) ## Max. value of RGB + diff = vmax - vmin ## Delta RGB value + + vsum = vmin + vmax + + l = vsum / 2 + + if diff == 0.0: ## This is a gray, no chroma... + return (0.0, 0.0, l) + ## + ## Chromatic data... + ## + + ## Saturation if l < 0.5: - v2 = l * (1.0 + s) + s = diff / vsum else: - v2 = (l + s) - (s * l) + s = diff / (2.0 - vsum) - v1 = 2.0 * l - v2 + dr = (((vmax - r) / 6) + (diff / 2)) / diff + dg = (((vmax - g) / 6) + (diff / 2)) / diff + db = (((vmax - b) / 6) + (diff / 2)) / diff - r = _hue2rgb(v1, v2, h + (1.0 / 3)) - g = _hue2rgb(v1, v2, h) - b = _hue2rgb(v1, v2, h - (1.0 / 3)) + if r == vmax: + h = db - dg + elif g == vmax: + h = (1.0 / 3) + dr - db + elif b == vmax: + h = (2.0 / 3) + dg - dr - return r, g, b + if h < 0: h += 1 + if h > 1: h -= 1 + + return (h, s, l) def rgb2hsl(rgb): @@ -468,6 +496,46 @@ def rgb2hsl(rgb): return (h, s, l) +def rgb2hex(rgb, force_long=False): + """Transform RGB tuple to hex RGB representation + + :param rgb: RGB 3-uple of float between 0 and 1 + :rtype: 3 hex char or 6 hex char string representation + + Usage + ----- + + >>> from colour import rgb2hex + + >>> rgb2hex((0.0,1.0,0.0)) + '#0f0' + + Rounding try to be as natural as possible: + + >>> rgb2hex((0.0,0.999999,1.0)) + '#0ff' + + And if not possible, the 6 hex char representation is used: + + >>> rgb2hex((0.23,1.0,1.0)) + '#3bffff' + + >>> rgb2hex((0.0,0.999999,1.0), force_long=True) + '#00ffff' + + """ + + hx = '#' + ''.join(["%02x" % int(c*255 + 0.5 - FLOAT_ERROR) for c in rgb]) + + if force_long == False and \ + hx[1] == hx[2] and \ + hx[3] == hx[4] and \ + hx[5] == hx[6]: + return '#' + hx[1] + hx[3] + hx[5] + + return hx + + def hsv2rgb(hsv): """Convert HSV representation towards RGB @@ -552,63 +620,6 @@ def hsv2rgb(hsv): b = _hue2rgb(v1, v2, h - (1.0 / 3)) -def _hue2rgb(v1, v2, vH): - """Private helper function (Do not call directly) - - :param vH: rotation around the chromatic circle (between 0..1) - - """ - - while vH < 0: vH += 1 - while vH > 1: vH -= 1 - - if 6 * vH < 1: return v1 + (v2 - v1) * 6 * vH - if 2 * vH < 1: return v2 - if 3 * vH < 2: return v1 + (v2 - v1) * ((2.0 / 3) - vH) * 6 - - return v1 - - -def rgb2hex(rgb, force_long=False): - """Transform RGB tuple to hex RGB representation - - :param rgb: RGB 3-uple of float between 0 and 1 - :rtype: 3 hex char or 6 hex char string representation - - Usage - ----- - - >>> from colour import rgb2hex - - >>> rgb2hex((0.0,1.0,0.0)) - '#0f0' - - Rounding try to be as natural as possible: - - >>> rgb2hex((0.0,0.999999,1.0)) - '#0ff' - - And if not possible, the 6 hex char representation is used: - - >>> rgb2hex((0.23,1.0,1.0)) - '#3bffff' - - >>> rgb2hex((0.0,0.999999,1.0), force_long=True) - '#00ffff' - - """ - - hx = '#' + ''.join(["%02x" % int(c*255 + 0.5 - FLOAT_ERROR) for c in rgb]) - - if force_long == False and \ - hx[1] == hx[2] and \ - hx[3] == hx[4] and \ - hx[5] == hx[6]: - return '#' + hx[1] + hx[3] + hx[5] - - return hx - - def hex2rgb(str_rgb): """Transform hex RGB representation to RGB tuple @@ -649,6 +660,121 @@ def hex2rgb(str_rgb): return tuple([float(int(v, 16)) / 255 for v in (r, g, b)]) +def hsl2rgb(hsl): + """Convert HSL representation towards RGB + + :param h: Hue, position around the chromatic circle (h=1 equiv h=0) + :param s: Saturation, color saturation (0=full gray, 1=full color) + :param l: Ligthness, Overhaul lightness (0=full black, 1=full white) + :rtype: 3-uple for RGB values in float between 0 and 1 + + Hue, Saturation, Range from Lightness is a float between 0 and 1 + + Note that Hue can be set to any value but as it is a rotation + around the chromatic circle, any value above 1 or below 0 can + be expressed by a value between 0 and 1 (Note that h=0 is equiv + to h=1). + + This algorithm came from: + http://www.easyrgb.com/index.php?X=MATH&H=19#text19 + + Here are some quick notion of HSL to RGB convertion: + + >>> from colour import hsl2rgb + + With a lightness put at 0, RGB is always rgbblack + + >>> hsl2rgb((0.0, 0.0, 0.0)) + (0.0, 0.0, 0.0) + >>> hsl2rgb((0.5, 0.0, 0.0)) + (0.0, 0.0, 0.0) + >>> hsl2rgb((0.5, 0.5, 0.0)) + (0.0, 0.0, 0.0) + + Same for lightness put at 1, RGB is always rgbwhite + + >>> hsl2rgb((0.0, 0.0, 1.0)) + (1.0, 1.0, 1.0) + >>> hsl2rgb((0.5, 0.0, 1.0)) + (1.0, 1.0, 1.0) + >>> hsl2rgb((0.5, 0.5, 1.0)) + (1.0, 1.0, 1.0) + + With saturation put at 0, the RGB should be equal to Lightness: + + >>> hsl2rgb((0.0, 0.0, 0.25)) + (0.25, 0.25, 0.25) + >>> hsl2rgb((0.5, 0.0, 0.5)) + (0.5, 0.5, 0.5) + >>> hsl2rgb((0.5, 0.0, 0.75)) + (0.75, 0.75, 0.75) + + With saturation put at 1, and lightness put to 0.5, we can find + normal full red, green, blue colors: + + >>> hsl2rgb((0 , 1.0, 0.5)) + (1.0, 0.0, 0.0) + >>> hsl2rgb((1 , 1.0, 0.5)) + (1.0, 0.0, 0.0) + >>> hsl2rgb((1.0/3 , 1.0, 0.5)) + (0.0, 1.0, 0.0) + >>> hsl2rgb((2.0/3 , 1.0, 0.5)) + (0.0, 0.0, 1.0) + + Of course: + >>> hsl2rgb((0.0, 2.0, 0.5)) # doctest: +ELLIPSIS + Traceback (most recent call last): + ... + ValueError: Saturation must be between 0 and 1. + + And: + >>> hsl2rgb((0.0, 0.0, 1.5)) # doctest: +ELLIPSIS + Traceback (most recent call last): + ... + ValueError: Lightness must be between 0 and 1. + + """ + h, s, l = [float(v) for v in hsl] + + if not (0.0 - FLOAT_ERROR <= s <= 1.0 + FLOAT_ERROR): + raise ValueError("Saturation must be between 0 and 1.") + if not (0.0 - FLOAT_ERROR <= l <= 1.0 + FLOAT_ERROR): + raise ValueError("Lightness must be between 0 and 1.") + + if s == 0: + return l, l, l + + if l < 0.5: + v2 = l * (1.0 + s) + else: + v2 = (l + s) - (s * l) + + v1 = 2.0 * l - v2 + + r = _hue2rgb(v1, v2, h + (1.0 / 3)) + g = _hue2rgb(v1, v2, h) + b = _hue2rgb(v1, v2, h - (1.0 / 3)) + + return r, g, b + + +def _hue2rgb(v1, v2, vH): + """Private helper function (Do not call directly) + + :param vH: rotation around the chromatic circle (between 0..1) + + """ + + while vH < 0: vH += 1 + while vH > 1: vH -= 1 + + if 6 * vH < 1: return v1 + (v2 - v1) * 6 * vH + if 2 * vH < 1: return v2 + if 3 * vH < 2: return v1 + (v2 - v1) * ((2.0 / 3) - vH) * 6 + + return v1 + + def hex2web(hex): """Converts HEX representation to WEB From 71c53965e2d634284768cc5f0ce4508b636426df Mon Sep 17 00:00:00 2001 From: Joshua Dong Date: Thu, 28 Jan 2016 13:29:21 -0600 Subject: [PATCH 3/4] Implemented hsv functionality. TODO: comments --- colour.py | 655 +++++++++++++++++++++++++++--------------------------- 1 file changed, 329 insertions(+), 326 deletions(-) diff --git a/colour.py b/colour.py index 81c8b34..b00cc02 100644 --- a/colour.py +++ b/colour.py @@ -9,12 +9,6 @@ Formats ------- -HSV: - 3-uple of Hue, Saturation, Value all between 0.0 and 1.0 - -HSL: - 3-uple of Hue, Saturation, Lightness all between 0.0 and 1.0 - RGB: 3-uple of Red, Green, Blue all between 0.0 and 1.0 @@ -25,6 +19,12 @@ WEB: string object that defaults to HEX representation or human if possible +HSL: + 3-uple of Hue, Saturation, Lightness all between 0.0 and 1.0 + +HSV: + 3-uple of Hue, Saturation, Value all between 0.0 and 1.0 + Usage ----- @@ -204,41 +204,6 @@ SHORT_HEX_COLOR = re.compile(r'^#[0-9a-fA-F]{3}$') -class C_HSV: - """HSV colors container - - Provides a quick color access. - - >>> from colour import HSV - - >>> HSV.WHITE - (0.0, 0.0, 1.0) - >>> HSV.BLUE - (0.0, 0.0, 1.0) # TODO: filli this in - - >>> HSV.DONOTEXISTS # doctest: +ELLIPSIS - Traceback (most recent call last): - ... - AttributeError: ... has no attribute 'DONOTEXISTS' - - """ - - def __getattr__(self, value): - label = value.lower() - if label in COLOR_NAME_TO_RGB: - return rgb2hsv(tuple(v / 255. for v in COLOR_NAME_TO_RGB[label])) - raise AttributeError("%s instance has no attribute %r" % (self.__class__, value)) - - -class C_HSL: - - def __getattr__(self, value): - label = value.lower() - if label in COLOR_NAME_TO_RGB: - return rgb2hsl(tuple(v / 255. for v in COLOR_NAME_TO_RGB[label])) - raise AttributeError("%s instance has no attribute %r" % (self.__class__, value)) - - class C_RGB: """RGB colors container @@ -285,114 +250,87 @@ def __getattr__(self, value): return rgb2hex(getattr(RGB, value)) -HSV = C_HSV() -HSL = C_HSL() -RGB = C_RGB() -HEX = C_HEX() - - -## -## Convertion function -## +class C_HSL: + def __getattr__(self, value): + label = value.lower() + if label in COLOR_NAME_TO_RGB: + return rgb2hsl(tuple(v / 255. for v in COLOR_NAME_TO_RGB[label])) + raise AttributeError("%s instance has no attribute %r" % (self.__class__, value)) -def rgb2hsv(rgb): - """Convert RGB representations to HSV - :param r: Red amount (float between 0 and 1) - :param g: Green amount (float between 0 and 1) - :param b: Blue amount (float between 0 and 1) - :rtype: 3-uple for HSV values in float between 0 and 1 +class C_HSV: + """HSV colors container - This algorithm came from: - http://www.easyrgb.com/index.php?X=MATH&H=20#text20 + Provides a quick color access. - Here are some quick notion of RGB to HSV convertion: + >>> from colour import HSV - >>> from colour import rgb2hsv + >>> HSV.WHITE + (0.0, 0.0, 1.0) + >>> HSV.BLUE # doctest: +ELLIPSIS + (0.666..., 1.0, 1.0) # TODO: filli this in - Note that if red amount is equal to green and blue, then you - should have a gray value (from black to white). + >>> HSV.DONOTEXISTS # doctest: +ELLIPSIS + Traceback (most recent call last): + ... + AttributeError: ... has no attribute 'DONOTEXISTS' + """ - >>> rgb2hsv((1.0, 1.0, 1.0)) # doctest: +ELLIPSIS - (..., 0.0, 1.0) #TODO: fill in - >>> rgb2hsv((0.5, 0.5, 0.5)) # doctest: +ELLIPSIS - (..., 0.0, 0.5) #TODO: fill in - >>> rgb2hsv((0.0, 0.0, 0.0)) # doctest: +ELLIPSIS - (..., 0.0, 0.0) #TODO: fill in + def __getattr__(self, value): + label = value.lower() + if label in COLOR_NAME_TO_RGB: + return rgb2hsv(tuple(v / 255. for v in COLOR_NAME_TO_RGB[label])) + raise AttributeError("%s instance has no attribute %r" % (self.__class__, value)) - If only one color is different from the others, it defines the - direct Hue: - >>> rgb2hsv((0.5, 0.5, 1.0)) # doctest: +ELLIPSIS - (0.66..., 1.0, 0.75) #TODO: fill in - >>> rgb2hsv((0.2, 0.1, 0.1)) # doctest: +ELLIPSIS - (0.0, 0.33..., 0.15...) #TODO: fill in +RGB = C_RGB() +HEX = C_HEX() +HSL = C_HSL() +HSV = C_HSV() - Having only one value set, you can check that: - >>> rgb2hsv((1.0, 0.0, 0.0)) - (0.0, 1.0, 0.5) #TODO: fill in - >>> rgb2hsv((0.0, 1.0, 0.0)) # doctest: +ELLIPSIS - (0.33..., 1.0, 0.5) #TODO: fill in - >>> rgb2hsv((0.0, 0.0, 1.0)) # doctest: +ELLIPSIS - (0.66..., 1.0, 0.5) #TODO: fill in +## +## Conversion functions +## +def rgb2hex(rgb, force_long=False): + """Transform RGB tuple to hex RGB representation - Bad input throws an exception: - >>> rgb2hsv((0.0, 2.0, 0.5)) # doctest: +ELLIPSIS - Traceback (most recent call last): - ... - ValueError: Green must be between 0 and 1. You provided 2.0. - >>> rgb2hsv((0.0, 0.0, 1.5)) # doctest: +ELLIPSIS - Traceback (most recent call last): - ... - ValueError: Blue must be between 0 and 1. You provided 1.5. + :param rgb: RGB 3-uple of float between 0 and 1 + :rtype: 3 hex char or 6 hex char string representation - """ - # TODO: implement - r, g, b = [float(v) for v in rgb] + Usage + ----- - for name, v in {'Red': r, 'Green': g, 'Blue': b}.items(): - if not (0 - FLOAT_ERROR <= v <= 1 + FLOAT_ERROR): - raise ValueError("%s must be between 0 and 1. You provided %r." - % (name, v)) + >>> from colour import rgb2hex - vmin = min(r, g, b) ## Min. value of RGB - vmax = max(r, g, b) ## Max. value of RGB - diff = vmax - vmin ## Delta RGB value + >>> rgb2hex((0.0,1.0,0.0)) + '#0f0' - vsum = vmin + vmax + Rounding try to be as natural as possible: - l = vsum / 2 + >>> rgb2hex((0.0,0.999999,1.0)) + '#0ff' - if diff == 0.0: ## This is a gray, no chroma... - return (0.0, 0.0, l) + And if not possible, the 6 hex char representation is used: - ## - ## Chromatic data... - ## + >>> rgb2hex((0.23,1.0,1.0)) + '#3bffff' - ## Saturation - if l < 0.5: - s = diff / vsum - else: - s = diff / (2.0 - vsum) + >>> rgb2hex((0.0,0.999999,1.0), force_long=True) + '#00ffff' - dr = (((vmax - r) / 6) + (diff / 2)) / diff - dg = (((vmax - g) / 6) + (diff / 2)) / diff - db = (((vmax - b) / 6) + (diff / 2)) / diff + """ - if r == vmax: - h = db - dg - elif g == vmax: - h = (1.0 / 3) + dr - db - elif b == vmax: - h = (2.0 / 3) + dg - dr + hx = '#' + ''.join(["%02x" % int(c*255 + 0.5 - FLOAT_ERROR) for c in rgb]) - if h < 0: h += 1 - if h > 1: h -= 1 + if force_long == False and \ + hx[1] == hx[2] and \ + hx[3] == hx[4] and \ + hx[5] == hx[6]: + return '#' + hx[1] + hx[3] + hx[5] - return (h, s, l) + return hx def rgb2hsl(rgb): @@ -496,128 +434,94 @@ def rgb2hsl(rgb): return (h, s, l) -def rgb2hex(rgb, force_long=False): - """Transform RGB tuple to hex RGB representation +def rgb2hsv(rgb): + """Convert RGB representations to HSV - :param rgb: RGB 3-uple of float between 0 and 1 - :rtype: 3 hex char or 6 hex char string representation + :param r: Red amount (float between 0 and 1) + :param g: Green amount (float between 0 and 1) + :param b: Blue amount (float between 0 and 1) + :rtype: 3-uple for HSV values in float between 0 and 1 - Usage - ----- + This algorithm came from: + http://www.easyrgb.com/index.php?X=MATH&H=20#text20 - >>> from colour import rgb2hex + Here are some quick notion of RGB to HSV convertion: - >>> rgb2hex((0.0,1.0,0.0)) - '#0f0' + >>> from colour import rgb2hsv - Rounding try to be as natural as possible: + Note that if red amount is equal to green and blue, then you + should have a gray value (from black to white). - >>> rgb2hex((0.0,0.999999,1.0)) - '#0ff' - And if not possible, the 6 hex char representation is used: + >>> rgb2hsv((1.0, 1.0, 1.0)) # doctest: +ELLIPSIS + (..., 0.0, 1.0) #TODO: fill in + >>> rgb2hsv((0.5, 0.5, 0.5)) # doctest: +ELLIPSIS + (..., 0.0, 0.5) #TODO: fill in + >>> rgb2hsv((0.0, 0.0, 0.0)) # doctest: +ELLIPSIS + (..., 0.0, 0.0) #TODO: fill in - >>> rgb2hex((0.23,1.0,1.0)) - '#3bffff' + If only one color is different from the others, it defines the + direct Hue: - >>> rgb2hex((0.0,0.999999,1.0), force_long=True) - '#00ffff' + >>> rgb2hsv((0.5, 0.5, 1.0)) # doctest: +ELLIPSIS + (0.66..., 1.0, 0.75) #TODO: fill in + >>> rgb2hsv((0.2, 0.1, 0.1)) # doctest: +ELLIPSIS + (0.0, 0.33..., 0.15...) #TODO: fill in - """ + Having only one value set, you can check that: - hx = '#' + ''.join(["%02x" % int(c*255 + 0.5 - FLOAT_ERROR) for c in rgb]) + >>> rgb2hsv((1.0, 0.0, 0.0)) + (0.0, 1.0, 0.5) #TODO: fill in + >>> rgb2hsv((0.0, 1.0, 0.0)) # doctest: +ELLIPSIS + (0.33..., 1.0, 0.5) #TODO: fill in + >>> rgb2hsv((0.0, 0.0, 1.0)) # doctest: +ELLIPSIS + (0.66..., 1.0, 0.5) #TODO: fill in - if force_long == False and \ - hx[1] == hx[2] and \ - hx[3] == hx[4] and \ - hx[5] == hx[6]: - return '#' + hx[1] + hx[3] + hx[5] + Bad input throws an exception: + >>> rgb2hsv((0.0, 2.0, 0.5)) # doctest: +ELLIPSIS + Traceback (most recent call last): + ... + ValueError: Green must be between 0 and 1. You provided 2.0. + >>> rgb2hsv((0.0, 0.0, 1.5)) # doctest: +ELLIPSIS + Traceback (most recent call last): + ... + ValueError: Blue must be between 0 and 1. You provided 1.5. - return hx + """ + r, g, b = [float(v) for v in rgb] + for name, v in {'Red': r, 'Green': g, 'Blue': b}.items(): + if not (0 - FLOAT_ERROR <= v <= 1 + FLOAT_ERROR): + raise ValueError("%s must be between 0 and 1. You provided %r." + % (name, v)) -def hsv2rgb(hsv): - """Convert HSV representation towards RGB + _min = min(r, g, b) + _max = max(r, g, b) + _delta = _max - _min - :param h: Hue, position around the chromatic circle (h=1 equiv h=0) - :param s: Saturation, color saturation (0=full gray, 1=full color) - :param v: Value, brightness value(0=full black, 1=full brightness) - :rtype: 3-uple for RGB values in float between 0 and 1 + v = _max - Hue, Saturation, and Value are floats between 0 and 1 - - Note that Hue can be set to any value but as it is a rotation - around the chromatic circle, any value above 1 or below 0 can - be expressed by a value between 0 and 1 (Note that h=0 is equiv - to h=1). - - This algorithm came from: - http://www.easyrgb.com/index.php?X=MATH&H=21#text21 - - Here are some examples of HSV to RGB convertion: - - >>> from colour import hsv2rgb - - TODO: finish examples - - >>> hsv2rgb((1.0, 1.0, 1.0)) # doctest: +ELLIPSIS - (..., 0.0, 1.0) - >>> hsv2rgb((0.5, 0.5, 0.5)) # doctest: +ELLIPSIS - (..., 0.0, 0.5) - >>> hsv2rgb((0.0, 0.0, 0.0)) # doctest: +ELLIPSIS - (..., 0.0, 0.0) - - If only one color is different from the others, it defines the - direct Hue: - - >>> hsv2rgb((0.5, 0.5, 1.0)) # doctest: +ELLIPSIS - (0.66..., 1.0, 0.75) - >>> hsv2rgb((0.2, 0.1, 0.1)) # doctest: +ELLIPSIS - (0.0, 0.33..., 0.15...) - - Having only one value set, you can check that: - - >>> hsv2rgb((1.0, 0.0, 0.0)) - (0.0, 1.0, 0.5) - >>> hsv2rgb((0.0, 1.0, 0.0)) # doctest: +ELLIPSIS - (0.33..., 1.0, 0.5) - >>> hsv2rgb((0.0, 0.0, 1.0)) # doctest: +ELLIPSIS - (0.66..., 1.0, 0.5) - - Of course: - >>> hsv2rgb((0.0, 2.0, 0.5)) # doctest: +ELLIPSIS - Traceback (most recent call last): - ... - ValueError: Green must be between 0 and 1. You provided 2.0. - - And: - >>> hsv2rgb((0.0, 0.0, 1.5)) # doctest: +ELLIPSIS - Traceback (most recent call last): - ... - ValueError: Blue must be between 0 and 1. You provided 1.5. - - """ - h, s, v = [float(v) for v in hsl] - - #TODO: implement this - if not (0.0 - FLOAT_ERROR <= s <= 1.0 + FLOAT_ERROR): - raise ValueError("Saturation must be between 0 and 1.") - if not (0.0 - FLOAT_ERROR <= l <= 1.0 + FLOAT_ERROR): - raise ValueError("Lightness must be between 0 and 1.") - - if s == 0: - return l, l, l - - if l < 0.5: - v2 = l * (1.0 + s) + if _delta == 0: # This is a gray (no chroma) + h, s = 0, 0 else: - v2 = (l + s) - (s * l) + s = _delta/_max + _dr = (((_max - r) / 6) + (_max / 2)) / _max + _dg = (((_max - g) / 6) + (_max / 2)) / _max + _db = (((_max - b) / 6) + (_max / 2)) / _max - v1 = 2.0 * l - v2 + if r == _max: + h = _db - _dg + elif g == _max: + h = (1 / 3) + r - b + elif b == _max: + h = (2 / 3) + g - r - r = _hue2rgb(v1, v2, h + (1.0 / 3)) - g = _hue2rgb(v1, v2, h) - b = _hue2rgb(v1, v2, h - (1.0 / 3)) + if h < 0: + h += 1 + if h > 1: + h -= 1 + + return h, s, l def hex2rgb(str_rgb): @@ -660,6 +564,115 @@ def hex2rgb(str_rgb): return tuple([float(int(v, 16)) / 255 for v in (r, g, b)]) +def hex2web(hex): + """Converts HEX representation to WEB + + :param rgb: 3 hex char or 6 hex char string representation + :rtype: web string representation (human readable if possible) + + WEB representation uses X11 rgb.txt to define convertion + between RGB and english color names. + + Usage + ===== + + >>> from colour import hex2web + + >>> hex2web('#ff0000') + 'red' + + >>> hex2web('#aaaaaa') + '#aaa' + + >>> hex2web('#abc') + '#abc' + + >>> hex2web('#acacac') + '#acacac' + + """ + dec_rgb = tuple(int(v * 255) for v in hex2rgb(hex)) + if dec_rgb in RGB_TO_COLOR_NAMES: + ## take the first one + color_name = RGB_TO_COLOR_NAMES[dec_rgb][0] + ## Enforce full lowercase for single worded color name. + return color_name if len(re.sub(r"[^A-Z]", "", color_name)) > 1 \ + else color_name.lower() + + # Hex format is verified by hex2rgb function. And should be 3 or 6 digit + if len(hex) == 7: + if hex[1] == hex[2] and \ + hex[3] == hex[4] and \ + hex[5] == hex[6]: + return '#' + hex[1] + hex[3] + hex[5] + return hex + + +def web2hex(web, force_long=False): + """Converts WEB representation to HEX + + :param rgb: web string representation (human readable if possible) + :rtype: 3 hex char or 6 hex char string representation + + WEB representation uses X11 rgb.txt to define convertion + between RGB and english color names. + + Usage + ===== + + >>> from colour import web2hex + + >>> web2hex('red') + '#f00' + + >>> web2hex('#aaa') + '#aaa' + + >>> web2hex('#foo') # doctest: +ELLIPSIS + Traceback (most recent call last): + ... + AttributeError: '#foo' is not in web format. Need 3 or 6 hex digit. + + >>> web2hex('#aaa', force_long=True) + '#aaaaaa' + + >>> web2hex('#aaaaaa') + '#aaaaaa' + + >>> web2hex('#aaaa') # doctest: +ELLIPSIS + Traceback (most recent call last): + ... + AttributeError: '#aaaa' is not in web format. Need 3 or 6 hex digit. + + >>> web2hex('pinky') # doctest: +ELLIPSIS + Traceback (most recent call last): + ... + ValueError: 'pinky' is not a recognized color. + + And color names are case insensitive: + + >>> Color('RED') + + + """ + if web.startswith('#'): + if (LONG_HEX_COLOR.match(web) or + (not force_long and SHORT_HEX_COLOR.match(web))): + return web.lower() + elif SHORT_HEX_COLOR.match(web) and force_long: + return '#' + ''.join([("%s" % (t, )) * 2 for t in web[1:]]) + raise AttributeError( + "%r is not in web format. Need 3 or 6 hex digit." % web) + + web = web.lower() + if web not in COLOR_NAME_TO_RGB: + raise ValueError("%r is not a recognized color." % web) + + ## convert dec to hex: + + return rgb2hex([float(int(v)) / 255 for v in COLOR_NAME_TO_RGB[web]], force_long) + + def hsl2rgb(hsl): """Convert HSL representation towards RGB @@ -758,140 +771,130 @@ def hsl2rgb(hsl): return r, g, b -def _hue2rgb(v1, v2, vH): - """Private helper function (Do not call directly) - - :param vH: rotation around the chromatic circle (between 0..1) - - """ - - while vH < 0: vH += 1 - while vH > 1: vH -= 1 - - if 6 * vH < 1: return v1 + (v2 - v1) * 6 * vH - if 2 * vH < 1: return v2 - if 3 * vH < 2: return v1 + (v2 - v1) * ((2.0 / 3) - vH) * 6 - - return v1 - - -def hex2web(hex): - """Converts HEX representation to WEB - - :param rgb: 3 hex char or 6 hex char string representation - :rtype: web string representation (human readable if possible) - - WEB representation uses X11 rgb.txt to define convertion - between RGB and english color names. - - Usage - ===== - - >>> from colour import hex2web - - >>> hex2web('#ff0000') - 'red' +def hsv2rgb(hsv): + """Convert HSV representation towards RGB - >>> hex2web('#aaaaaa') - '#aaa' + :param h: Hue, position around the chromatic circle (h=1 equiv h=0) + :param s: Saturation, color saturation (0=full gray, 1=full color) + :param v: Value, brightness value(0=full black, 1=full brightness) + :rtype: 3-uple for RGB values in float between 0 and 1 - >>> hex2web('#abc') - '#abc' + Hue, Saturation, and Value are floats between 0 and 1 - >>> hex2web('#acacac') - '#acacac' + Note that Hue can be set to any value but as it is a rotation + around the chromatic circle, any value above 1 or below 0 can + be expressed by a value between 0 and 1 (Note that h=0 is equiv + to h=1). - """ - dec_rgb = tuple(int(v * 255) for v in hex2rgb(hex)) - if dec_rgb in RGB_TO_COLOR_NAMES: - ## take the first one - color_name = RGB_TO_COLOR_NAMES[dec_rgb][0] - ## Enforce full lowercase for single worded color name. - return color_name if len(re.sub(r"[^A-Z]", "", color_name)) > 1 \ - else color_name.lower() + This algorithm came from: + http://www.easyrgb.com/index.php?X=MATH&H=21#text21 - # Hex format is verified by hex2rgb function. And should be 3 or 6 digit - if len(hex) == 7: - if hex[1] == hex[2] and \ - hex[3] == hex[4] and \ - hex[5] == hex[6]: - return '#' + hex[1] + hex[3] + hex[5] - return hex + Here are some examples of HSV to RGB convertion: + >>> from colour import hsv2rgb -def web2hex(web, force_long=False): - """Converts WEB representation to HEX + TODO: finish examples - :param rgb: web string representation (human readable if possible) - :rtype: 3 hex char or 6 hex char string representation + >>> hsv2rgb((1.0, 1.0, 1.0)) # doctest: +ELLIPSIS + (..., 0.0, 1.0) + >>> hsv2rgb((0.5, 0.5, 0.5)) # doctest: +ELLIPSIS + (..., 0.0, 0.5) + >>> hsv2rgb((0.0, 0.0, 0.0)) # doctest: +ELLIPSIS + (..., 0.0, 0.0) - WEB representation uses X11 rgb.txt to define convertion - between RGB and english color names. + If only one color is different from the others, it defines the + direct Hue: - Usage - ===== + >>> hsv2rgb((0.5, 0.5, 1.0)) # doctest: +ELLIPSIS + (0.66..., 1.0, 0.75) + >>> hsv2rgb((0.2, 0.1, 0.1)) # doctest: +ELLIPSIS + (0.0, 0.33..., 0.15...) - >>> from colour import web2hex + Having only one value set, you can check that: - >>> web2hex('red') - '#f00' + >>> hsv2rgb((1.0, 0.0, 0.0)) + (0.0, 1.0, 0.5) + >>> hsv2rgb((0.0, 1.0, 0.0)) # doctest: +ELLIPSIS + (0.33..., 1.0, 0.5) + >>> hsv2rgb((0.0, 0.0, 1.0)) # doctest: +ELLIPSIS + (0.66..., 1.0, 0.5) - >>> web2hex('#aaa') - '#aaa' + Of course: + >>> hsv2rgb((0.0, 2.0, 0.5)) # doctest: +ELLIPSIS + Traceback (most recent call last): + ... + ValueError: Green must be between 0 and 1. You provided 2.0. - >>> web2hex('#foo') # doctest: +ELLIPSIS + And: + >>> hsv2rgb((0.0, 0.0, 1.5)) # doctest: +ELLIPSIS Traceback (most recent call last): ... - AttributeError: '#foo' is not in web format. Need 3 or 6 hex digit. + ValueError: Blue must be between 0 and 1. You provided 1.5. - >>> web2hex('#aaa', force_long=True) - '#aaaaaa' + """ + h, s, v = [float(v) for v in hsl] - >>> web2hex('#aaaaaa') - '#aaaaaa' + if not (0.0 - FLOAT_ERROR <= s <= 1.0 + FLOAT_ERROR): + raise ValueError("Saturation must be between 0 and 1.") + if not (0.0 - FLOAT_ERROR <= v <= 1.0 + FLOAT_ERROR): + raise ValueError("Value must be between 0 and 1.") + + if s == 0: # HSV from 0 to 1 + return v, v, v + + _h = h*6 + if (_h == 6) _h = 0 # H must be < 1 + + _i = int(_h) # Or ... var_i = floor( var_h ) + _1 = v * (1 - s) + _2 = v * (1 - s * (_h - _i)) + _3 = v * (1 - s * (1 - (_h - _i))) + + if _i == 0: + r, g, b = v, _3, _1 + elif _i == 1: + r, g, b = _2, v, _1 + elif _i == 2: + r, g, b = _1, v, _3 + elif _i == 3: + r, g, b = _1, _2, v + elif _i == 4: + r, g, b = _3, _1, v + else: + r, g, b = v, _1, _2 - >>> web2hex('#aaaa') # doctest: +ELLIPSIS - Traceback (most recent call last): - ... - AttributeError: '#aaaa' is not in web format. Need 3 or 6 hex digit. + return r, g, b - >>> web2hex('pinky') # doctest: +ELLIPSIS - Traceback (most recent call last): - ... - ValueError: 'pinky' is not a recognized color. - And color names are case insensitive: +def _hue2rgb(v1, v2, vH): + """Private helper function for hsl2rgb - >>> Color('RED') - + :param vH: rotation around the chromatic circle (between 0..1) """ - if web.startswith('#'): - if (LONG_HEX_COLOR.match(web) or - (not force_long and SHORT_HEX_COLOR.match(web))): - return web.lower() - elif SHORT_HEX_COLOR.match(web) and force_long: - return '#' + ''.join([("%s" % (t, )) * 2 for t in web[1:]]) - raise AttributeError( - "%r is not in web format. Need 3 or 6 hex digit." % web) - web = web.lower() - if web not in COLOR_NAME_TO_RGB: - raise ValueError("%r is not a recognized color." % web) + while vH < 0: vH += 1 + while vH > 1: vH -= 1 - ## convert dec to hex: + if 6 * vH < 1: return v1 + (v2 - v1) * 6 * vH + if 2 * vH < 1: return v2 + if 3 * vH < 2: return v1 + (v2 - v1) * ((2.0 / 3) - vH) * 6 - return rgb2hex([float(int(v)) / 255 for v in COLOR_NAME_TO_RGB[web]], force_long) + return v1 ## Missing functions convertion - -hsl2hex = lambda x: rgb2hex(hsl2rgb(x)) -hex2hsl = lambda x: rgb2hsl(hex2rgb(x)) rgb2web = lambda x: hex2web(rgb2hex(x)) +hex2hsl = lambda x: rgb2hsl(hex2rgb(x)) +hex2hsv = lambda x: rgb2hsv(hex2rgb(x)) web2rgb = lambda x: hex2rgb(web2hex(x)) web2hsl = lambda x: rgb2hsl(web2rgb(x)) +web2hsv = lambda x: rgb2hsv(web2rgb(x)) +hsl2hex = lambda x: rgb2hex(hsl2rgb(x)) hsl2web = lambda x: rgb2web(hsl2rgb(x)) +hsl2hsv = lambda x: rgb2hsv(hsl2rgb(x)) +hsv2hex = lambda x: rgb2hex(hsv2rgb(x)) +hsv2hsl = lambda x: rgb2hsl(hsv2rgb(x)) def color_scale(begin_hsl, end_hsl, nb): From b461dc72ade810c73c6d217c85c58ea8b7db12b1 Mon Sep 17 00:00:00 2001 From: Joshua Date: Mon, 17 Oct 2016 12:34:00 -0500 Subject: [PATCH 4/4] hsv in progress --- colour.py | 31 ++++++++++++++++--------------- setup.cfg | 16 ++++++++-------- setup.py | 2 +- 3 files changed, 25 insertions(+), 24 deletions(-) diff --git a/colour.py b/colour.py index b00cc02..d3c3f4a 100644 --- a/colour.py +++ b/colour.py @@ -268,7 +268,7 @@ class C_HSV: >>> HSV.WHITE (0.0, 0.0, 1.0) >>> HSV.BLUE # doctest: +ELLIPSIS - (0.666..., 1.0, 1.0) # TODO: filli this in + (0.666..., 1.0, 1.0) >>> HSV.DONOTEXISTS # doctest: +ELLIPSIS Traceback (most recent call last): @@ -453,29 +453,29 @@ def rgb2hsv(rgb): should have a gray value (from black to white). - >>> rgb2hsv((1.0, 1.0, 1.0)) # doctest: +ELLIPSIS - (..., 0.0, 1.0) #TODO: fill in - >>> rgb2hsv((0.5, 0.5, 0.5)) # doctest: +ELLIPSIS - (..., 0.0, 0.5) #TODO: fill in - >>> rgb2hsv((0.0, 0.0, 0.0)) # doctest: +ELLIPSIS - (..., 0.0, 0.0) #TODO: fill in + >>> rgb2hsv((1.0, 1.0, 1.0)) + (0, 0, 1.0) + >>> rgb2hsv((0.5, 0.5, 0.5)) + (0, 0, 0.5) + >>> rgb2hsv((0.0, 0.0, 0.0)) + (0, 0, 0.0) If only one color is different from the others, it defines the direct Hue: >>> rgb2hsv((0.5, 0.5, 1.0)) # doctest: +ELLIPSIS - (0.66..., 1.0, 0.75) #TODO: fill in - >>> rgb2hsv((0.2, 0.1, 0.1)) # doctest: +ELLIPSIS - (0.0, 0.33..., 0.15...) #TODO: fill in + (0.66..., 0.5, 1.0) + >>> rgb2hsv((0.2, 0.1, 0.1)) + (0.0, 0.5, 0.2) Having only one value set, you can check that: >>> rgb2hsv((1.0, 0.0, 0.0)) - (0.0, 1.0, 0.5) #TODO: fill in + (0.0, 1.0, 1.0) >>> rgb2hsv((0.0, 1.0, 0.0)) # doctest: +ELLIPSIS - (0.33..., 1.0, 0.5) #TODO: fill in + (0.33..., 1.0, 1.0) >>> rgb2hsv((0.0, 0.0, 1.0)) # doctest: +ELLIPSIS - (0.66..., 1.0, 0.5) #TODO: fill in + (0.66..., 1.0, 1.0) Bad input throws an exception: >>> rgb2hsv((0.0, 2.0, 0.5)) # doctest: +ELLIPSIS @@ -521,7 +521,7 @@ def rgb2hsv(rgb): if h > 1: h -= 1 - return h, s, l + return h, s, v def hex2rgb(str_rgb): @@ -843,7 +843,8 @@ def hsv2rgb(hsv): return v, v, v _h = h*6 - if (_h == 6) _h = 0 # H must be < 1 + if _h == 6: + _h = 0 # H must be < 1 _i = int(_h) # Or ... var_i = floor( var_h ) _1 = v * (1 - s) diff --git a/setup.cfg b/setup.cfg index cf075b0..db27547 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,7 +1,7 @@ [metadata] -name = %%name%% -version = %%version%% -summary = %%description%% +name = colour +version = 0.1.2.dev201601281329 +summary = converts and manipulates various color representation (HSL, RVB, web, X11, ...) description-file = README.rst CHANGELOG.rst @@ -9,9 +9,9 @@ description-file = requires-dist = ## sdist info -author = %%author%% -author_email = %%email%% -home_page = http://github.com/vaab/%%name%% +author = Valentin LAB +author_email = valentin.lab@kalysto.org +home_page = http://github.com/vaab/colour classifier = Programming Language :: Python Topic :: Software Development :: Libraries :: Python Modules @@ -21,7 +21,7 @@ classifier = Intended Audience :: Developers [files] -modules = %%name%% +modules = colour #packages-root = src #packages = # colour @@ -33,7 +33,7 @@ extra_files = # [entry_points] # console_scripts = -# cmd1 = %%name%%.example:run +# cmd1 = colour.example:run [nosetests] verbosity = 3 diff --git a/setup.py b/setup.py index 5c94cfe..83a8432 100644 --- a/setup.py +++ b/setup.py @@ -15,7 +15,7 @@ ## Ensure that ``./autogen.sh`` is run prior to using ``setup.py`` ## -if "%%short-version%%".startswith("%%"): +if "0.1.2".startswith("%%"): import os.path import sys if not os.path.exists('./autogen.sh'):