pax_global_header00006660000000000000000000000064132217350730014515gustar00rootroot0000000000000052 comment=ca7e1abc7e7106dbdaf316577b2661296baa9719 python-colour-0.1.5/000077500000000000000000000000001322173507300143425ustar00rootroot00000000000000python-colour-0.1.5/CHANGELOG.rst000066400000000000000000000044171322173507300163710ustar00rootroot00000000000000Changelog ========= 0.1.4 (2017-04-19) ------------------ Fix ~~~ - ``rgb2hsl`` would produce invalid hsl triplet when red, blue, green component would be all very close to ``1.0``. (fixes #30) [Valentin Lab] Typically, saturation would shoot out of range 0.0..1.0. That could then lead to exceptions being casts afterwards when trying to reconvert this HSL triplet to RGB values. 0.1.3 (2017-04-08) ------------------ Fix ~~~ - Unexpected behavior with ``!=`` operator. (fixes #26) [Valentin Lab] - Added mention of the ``hex_l`` property. (fixes #27) [Valentin Lab] 0.1.2 (2015-09-15) ------------------ Fix ~~~ - Support for corner case 1-wide ``range_to`` color scale. (fixes #18) [Valentin Lab] 0.1.1 (2015-03-29) ------------------ Fix ~~~ - Avoid casting an exception when comparing to non-``Colour`` instances. (fixes #14) [Riziq Sayegh] 0.0.6 (2014-11-18) ------------------ New ~~~ - Provide all missing *2* function by combination with other existing ones (fixes #13). [Valentin Lab] - Provide full access to any color name in HSL, RGB, HEX convenience instances. [Valentin Lab] Now you can call ``colour.HSL.cyan``, or ``colour.HEX.red`` for a direct encoding of ``human`` colour labels to the 3 representations. 0.0.5 (2013-09-16) ------------------ New ~~~ - Color names are case insensitive. [Chris Priest] The color-name structure have their names capitalized. And color names that are made of only one word will be displayed lowercased. Fix ~~~ - Now using W3C color recommandation. [Chris Priest] Was using X11 color scheme before, which is slightly different from W3C web color specifications. - Inconsistency in licence information (removed GPL mention). (fixes #8) [Valentin Lab] - Removed ``gitchangelog`` from ``setup.py`` require list. (fixes #9) [Valentin Lab] 0.0.4 (2013-06-21) ------------------ New ~~~ - Added ``make_color_factory`` to customize some common color attributes. [Valentin Lab] - Pick color to identify any python object (fixes #6) [Jonathan Ballet] - Equality support between colors, customizable if needed. (fixes #3) [Valentin Lab] 0.0.3 (2013-06-19) ------------------ New ~~~ - Colour is now compatible with python3. [Ryan Leckey] 0.0.1 (2012-06-11) ------------------ - First import. [Valentin Lab] python-colour-0.1.5/LICENSE000066400000000000000000000024301322173507300153460ustar00rootroot00000000000000Copyright (c) 2012-2017, Valentin Lab All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. python-colour-0.1.5/MANIFEST.in000066400000000000000000000000261322173507300160760ustar00rootroot00000000000000include *.rst LICENSE python-colour-0.1.5/PKG-INFO000066400000000000000000000550221322173507300154430ustar00rootroot00000000000000Metadata-Version: 1.1 Name: colour Version: 0.1.5 Summary: converts and manipulates various color representation (HSL, RVB, web, X11, ...) Home-page: http://github.com/vaab/colour Author: Valentin LAB Author-email: valentin.lab@kalysto.org License: BSD 3-Clause License Description: ====== Colour ====== .. image:: http://img.shields.io/pypi/v/colour.svg?style=flat :target: https://pypi.python.org/pypi/colour/ :alt: Latest PyPI version .. image:: https://img.shields.io/pypi/l/gitchangelog.svg?style=flat :target: https://github.com/vaab/gitchangelog/blob/master/LICENSE :alt: License .. image:: https://img.shields.io/pypi/pyversions/gitchangelog.svg?style=flat :target: https://pypi.python.org/pypi/gitchangelog/ :alt: Compatible python versions .. image:: http://img.shields.io/pypi/dm/colour.svg?style=flat :target: https://pypi.python.org/pypi/colour/ :alt: Number of PyPI downloads .. image:: http://img.shields.io/travis/vaab/colour/master.svg?style=flat :target: https://travis-ci.org/vaab/colour/ :alt: Travis CI build status .. image:: https://img.shields.io/appveyor/ci/vaab/colour.svg :target: https://ci.appveyor.com/project/vaab/colour/branch/master :alt: Appveyor CI build status .. image:: http://img.shields.io/codecov/c/github/vaab/colour.svg?style=flat :target: https://codecov.io/gh/vaab/colour/ :alt: Test coverage Converts and manipulates common color representation (RGB, HSL, web, ...) Feature ======= - Damn simple and pythonic way to manipulate color representation (see examples below) - Full conversion between RGB, HSL, 6-digit hex, 3-digit hex, human color - One object (``Color``) or bunch of single purpose function (``rgb2hex``, ``hsl2rgb`` ...) - ``web`` format that use the smallest representation between 6-digit (e.g. ``#fa3b2c``), 3-digit (e.g. ``#fbb``), fully spelled color (e.g. ``white``), following `W3C color naming`_ for compatible CSS or HTML color specifications. - smooth intuitive color scale generation choosing N color gradients. - can pick colors for you to identify objects of your application. .. _W3C color naming: http://www.w3.org/TR/css3-color/#svg-color Installation ============ You don't need to download the GIT version of the code as ``colour`` is available on the PyPI. So you should be able to run:: pip install colour If you have downloaded the GIT sources, then you could add the ``colour.py`` directly to one of your ``site-packages`` (thanks to a symlink). Or install the current version via traditional:: python setup.py install And if you don't have the GIT sources but would like to get the latest master or branch from github, you could also:: pip install git+https://github.com/vaab/colour Or even select a specific revision (branch/tag/commit):: pip install git+https://github.com/vaab/colour@master Usage ===== To get complete demo of each function, please read the source code which is heavily documented and provide a lot of examples in doctest format. Here is a reduced sample of a common usage scenario: Instantiation ------------- Let's create blue color:: >>> from colour import Color >>> c = Color("blue") >>> c Please note that all of these are equivalent examples to create the red color:: Color("red") ## human, web compatible representation Color(red=1) ## default amount of blue and green is 0.0 Color("blue", hue=0) ## hue of blue is 0.66, hue of red is 0.0 Color("#f00") ## standard 3 hex digit web compatible representation Color("#ff0000") ## standard 6 hex digit web compatible representation Color(hue=0, saturation=1, luminance=0.5) Color(hsl=(0, 1, 0.5)) ## full 3-uple HSL specification Color(rgb=(1, 0, 0)) ## full 3-uple RGB specification Color(Color("red")) ## recursion doesn't break object Reading values -------------- Several representations are accessible:: >>> c.hex '#00f' >>> c.hsl # doctest: +ELLIPSIS (0.66..., 1.0, 0.5) >>> c.rgb (0.0, 0.0, 1.0) And their different parts are also independently accessible, as the different amount of red, blue, green, in the RGB format:: >>> c.red 0.0 >>> c.blue 1.0 >>> c.green 0.0 Or the hue, saturation and luminance of the HSL representation:: >>> c.hue # doctest: +ELLIPSIS 0.66... >>> c.saturation 1.0 >>> c.luminance 0.5 A note on the ``.hex`` property, it'll return the smallest valid value when possible. If you are only interested by the long value, use ``.hex_l``:: >>> c.hex_l '#0000ff' Modifying color objects ----------------------- All of these properties are read/write, so let's add some red to this color:: >>> c.red = 1 >>> c We might want to de-saturate this color:: >>> c.saturation = 0.5 >>> c And of course, the string conversion will give the web representation which is human, or 3-digit, or 6-digit hex representation depending which is usable:: >>> "%s" % c '#bf40bf' >>> c.luminance = 1 >>> "%s" % c 'white' Ranges of colors ---------------- You can get some color scale of variation between two ``Color`` objects quite easily. Here, is the color scale of the rainbow between red and blue:: >>> red = Color("red") >>> blue = Color("blue") >>> list(red.range_to(blue, 5)) [, , , , ] Or the different amount of gray between black and white:: >>> black = Color("black") >>> white = Color("white") >>> list(black.range_to(white, 6)) [, , , , , ] If you have to create graphical representation with color scale between red and green ('lime' color is full green):: >>> lime = Color("lime") >>> list(red.range_to(lime, 5)) [, , , , ] Notice how naturally, the yellow is displayed in human format and in the middle of the scale. And that the quite unusual (but compatible) 'chartreuse' color specification has been used in place of the hexadecimal representation. Color comparison ---------------- Sane default ~~~~~~~~~~~~ Color comparison is a vast subject. However, it might seem quite straightforward for you. ``Colour`` uses a configurable default way of comparing color that might suit your needs:: >>> Color("red") == Color("#f00") == Color("blue", hue=0) True The default comparison algorithm focuses only on the "web" representation which is equivalent to comparing the long hex representation (e.g. #FF0000) or to be more specific, it is equivalent to compare the amount of red, green, and blue composition of the RGB representation, each of these value being quantized to a 256 value scale. This default comparison is a practical and convenient way to measure the actual color equivalence on your screen, or in your video card memory. But this comparison wouldn't make the difference between a black red, and a black blue, which both are black:: >>> black_red = Color("red", luminance=0) >>> black_blue = Color("blue", luminance=0) >>> black_red == black_blue True Customization ~~~~~~~~~~~~~ But, this is not the sole way to compare two colors. As I'm quite lazy, I'm providing you a way to customize it to your needs. Thus:: >>> from colour import RGB_equivalence, HSL_equivalence >>> black_red = Color("red", luminance=0, equality=HSL_equivalence) >>> black_blue = Color("blue", luminance=0, equality=HSL_equivalence) >>> black_red == black_blue False As you might have already guessed, the sane default is ``RGB_equivalence``, so:: >>> black_red = Color("red", luminance=0, equality=RGB_equivalence) >>> black_blue = Color("blue", luminance=0, equality=RGB_equivalence) >>> black_red == black_blue True Here's how you could implement your unique comparison function:: >>> saturation_equivalence = lambda c1, c2: c1.saturation == c2.saturation >>> red = Color("red", equality=saturation_equivalence) >>> blue = Color("blue", equality=saturation_equivalence) >>> white = Color("white", equality=saturation_equivalence) >>> red == blue True >>> white == red False Note: When comparing 2 colors, *only* the equality function *of the first color will be used*. Thus:: >>> black_red = Color("red", luminance=0, equality=RGB_equivalence) >>> black_blue = Color("blue", luminance=0, equality=HSL_equivalence) >>> black_red == black_blue True But reverse operation is not equivalent !:: >>> black_blue == black_red False Equality to non-Colour objects ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ As a side note, whatever your custom equality function is, it won't be used if you compare to anything else than a ``Colour`` instance:: >>> red = Color("red", equality=lambda c1, c2: True) >>> blue = Color("blue", equality=lambda c1, c2: True) Note that these instances would compare as equal to any other color:: >>> red == blue True But on another non-Colour object:: >>> red == None False >>> red != None True Actually, ``Colour`` instances will, politely enough, leave the other side of the equality have a chance to decide of the output, (by executing its own ``__eq__``), so:: >>> class OtherColorImplem(object): ... def __init__(self, color): ... self.color = color ... def __eq__(self, other): ... return self.color == other.web >>> alien_red = OtherColorImplem("red") >>> red == alien_red True >>> blue == alien_red False And inequality (using ``__ne__``) are also polite:: >>> class AnotherColorImplem(OtherColorImplem): ... def __ne__(self, other): ... return self.color != other.web >>> new_alien_red = AnotherColorImplem("red") >>> red != new_alien_red False >>> blue != new_alien_red True Picking arbitrary color for a python object ------------------------------------------- Basic Usage ~~~~~~~~~~~ Sometimes, you just want to pick a color for an object in your application often to visually identify this object. Thus, the picked color should be the same for same objects, and different for different object:: >>> foo = object() >>> bar = object() >>> Color(pick_for=foo) # doctest: +ELLIPSIS >>> Color(pick_for=foo) == Color(pick_for=foo) True >>> Color(pick_for=foo) == Color(pick_for=bar) False Of course, although there's a tiny probability that different strings yield the same color, most of the time, different inputs will produce different colors. Advanced Usage ~~~~~~~~~~~~~~ You can customize your color picking algorithm by providing a ``picker``. A ``picker`` is a callable that takes an object, and returns something that can be instantiated as a color by ``Color``:: >>> my_picker = lambda obj: "red" if isinstance(obj, int) else "blue" >>> Color(pick_for=3, picker=my_picker, pick_key=None) >>> Color(pick_for="foo", picker=my_picker, pick_key=None) You might want to use a particular picker, but enforce how the picker will identify two object as the same (or not). So there's a ``pick_key`` attribute that is provided and defaults as equivalent of ``hash`` method and if hash is not supported by your object, it'll default to the ``str`` of your object salted with the class name. Thus:: >>> class MyObj(str): pass >>> my_obj_color = Color(pick_for=MyObj("foo")) >>> my_str_color = Color(pick_for="foo") >>> my_obj_color == my_str_color False Please make sure your object is hashable or "stringable" before using the ``RGB_color_picker`` picking mechanism or provide another color picker. Nearly all python object are hashable by default so this shouldn't be an issue (e.g. instances of ``object`` and subclasses are hashable). Neither ``hash`` nor ``str`` are perfect solution. So feel free to use ``pick_key`` at ``Color`` instantiation time to set your way to identify objects, for instance:: >>> a = object() >>> b = object() >>> Color(pick_for=a, pick_key=id) == Color(pick_for=b, pick_key=id) False When choosing a pick key, you should closely consider if you want your color to be consistent between runs (this is NOT the case with the last example), or consistent with the content of your object if it is a mutable object. Default value of ``pick_key`` and ``picker`` ensures that the same color will be attributed to same object between different run on different computer for most python object. Color factory ------------- As you might have noticed, there are few attributes that you might want to see attached to all of your colors as ``equality`` for equality comparison support, or ``picker``, ``pick_key`` to configure your object color picker. You can create a customized ``Color`` factory thanks to the ``make_color_factory``:: >>> from colour import make_color_factory, HSL_equivalence, RGB_color_picker >>> get_color = make_color_factory( ... equality=HSL_equivalence, ... picker=RGB_color_picker, ... pick_key=str, ... ) All color created thanks to ``CustomColor`` class instead of the default one would get the specified attributes by default:: >>> black_red = get_color("red", luminance=0) >>> black_blue = get_color("blue", luminance=0) Of course, these are always instances of ``Color`` class:: >>> isinstance(black_red, Color) True Equality was changed from normal defaults, so:: >>> black_red == black_blue False This because the default equivalence of ``Color`` was set to ``HSL_equivalence``. Contributing ============ Any suggestion or issue is welcome. Push request are very welcome, please check out the guidelines. Push Request Guidelines ----------------------- You can send any code. I'll look at it and will integrate it myself in the code base and leave you as the author. This process can take time and it'll take less time if you follow the following guidelines: - check your code with PEP8 or pylint. Try to stick to 80 columns wide. - separate your commits per smallest concern. - each commit should pass the tests (to allow easy bisect) - each functionality/bugfix commit should contain the code, tests, and doc. - prior minor commit with typographic or code cosmetic changes are very welcome. These should be tagged in their commit summary with ``!minor``. - the commit message should follow gitchangelog rules (check the git log to get examples) - if the commit fixes an issue or finished the implementation of a feature, please mention it in the summary. If you have some questions about guidelines which is not answered here, please check the current ``git log``, you might find previous commit that would show you how to deal with your issue. License ======= Copyright (c) 2012-2017 Valentin Lab. Licensed under the `BSD License`_. .. _BSD License: http://raw.github.com/vaab/colour/master/LICENSE Changelog ========= 0.1.4 (2017-04-19) ------------------ Fix ~~~ - ``rgb2hsl`` would produce invalid hsl triplet when red, blue, green component would be all very close to ``1.0``. (fixes #30) [Valentin Lab] Typically, saturation would shoot out of range 0.0..1.0. That could then lead to exceptions being casts afterwards when trying to reconvert this HSL triplet to RGB values. 0.1.3 (2017-04-08) ------------------ Fix ~~~ - Unexpected behavior with ``!=`` operator. (fixes #26) [Valentin Lab] - Added mention of the ``hex_l`` property. (fixes #27) [Valentin Lab] 0.1.2 (2015-09-15) ------------------ Fix ~~~ - Support for corner case 1-wide ``range_to`` color scale. (fixes #18) [Valentin Lab] 0.1.1 (2015-03-29) ------------------ Fix ~~~ - Avoid casting an exception when comparing to non-``Colour`` instances. (fixes #14) [Riziq Sayegh] 0.0.6 (2014-11-18) ------------------ New ~~~ - Provide all missing *2* function by combination with other existing ones (fixes #13). [Valentin Lab] - Provide full access to any color name in HSL, RGB, HEX convenience instances. [Valentin Lab] Now you can call ``colour.HSL.cyan``, or ``colour.HEX.red`` for a direct encoding of ``human`` colour labels to the 3 representations. 0.0.5 (2013-09-16) ------------------ New ~~~ - Color names are case insensitive. [Chris Priest] The color-name structure have their names capitalized. And color names that are made of only one word will be displayed lowercased. Fix ~~~ - Now using W3C color recommandation. [Chris Priest] Was using X11 color scheme before, which is slightly different from W3C web color specifications. - Inconsistency in licence information (removed GPL mention). (fixes #8) [Valentin Lab] - Removed ``gitchangelog`` from ``setup.py`` require list. (fixes #9) [Valentin Lab] 0.0.4 (2013-06-21) ------------------ New ~~~ - Added ``make_color_factory`` to customize some common color attributes. [Valentin Lab] - Pick color to identify any python object (fixes #6) [Jonathan Ballet] - Equality support between colors, customizable if needed. (fixes #3) [Valentin Lab] 0.0.3 (2013-06-19) ------------------ New ~~~ - Colour is now compatible with python3. [Ryan Leckey] 0.0.1 (2012-06-11) ------------------ - First import. [Valentin Lab] TODO ==== - ANSI 16-color and 256-color escape sequence generation - YUV, HSV, CMYK support Platform: UNKNOWN Classifier: Programming Language :: Python Classifier: Topic :: Software Development :: Libraries :: Python Modules Classifier: Development Status :: 3 - Alpha Classifier: License :: OSI Approved :: BSD License Classifier: Intended Audience :: Developers Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 python-colour-0.1.5/README.rst000066400000000000000000000350761322173507300160440ustar00rootroot00000000000000====== Colour ====== .. image:: http://img.shields.io/pypi/v/colour.svg?style=flat :target: https://pypi.python.org/pypi/colour/ :alt: Latest PyPI version .. image:: https://img.shields.io/pypi/l/gitchangelog.svg?style=flat :target: https://github.com/vaab/gitchangelog/blob/master/LICENSE :alt: License .. image:: https://img.shields.io/pypi/pyversions/gitchangelog.svg?style=flat :target: https://pypi.python.org/pypi/gitchangelog/ :alt: Compatible python versions .. image:: http://img.shields.io/pypi/dm/colour.svg?style=flat :target: https://pypi.python.org/pypi/colour/ :alt: Number of PyPI downloads .. image:: http://img.shields.io/travis/vaab/colour/master.svg?style=flat :target: https://travis-ci.org/vaab/colour/ :alt: Travis CI build status .. image:: https://img.shields.io/appveyor/ci/vaab/colour.svg :target: https://ci.appveyor.com/project/vaab/colour/branch/master :alt: Appveyor CI build status .. image:: http://img.shields.io/codecov/c/github/vaab/colour.svg?style=flat :target: https://codecov.io/gh/vaab/colour/ :alt: Test coverage Converts and manipulates common color representation (RGB, HSL, web, ...) Feature ======= - Damn simple and pythonic way to manipulate color representation (see examples below) - Full conversion between RGB, HSL, 6-digit hex, 3-digit hex, human color - One object (``Color``) or bunch of single purpose function (``rgb2hex``, ``hsl2rgb`` ...) - ``web`` format that use the smallest representation between 6-digit (e.g. ``#fa3b2c``), 3-digit (e.g. ``#fbb``), fully spelled color (e.g. ``white``), following `W3C color naming`_ for compatible CSS or HTML color specifications. - smooth intuitive color scale generation choosing N color gradients. - can pick colors for you to identify objects of your application. .. _W3C color naming: http://www.w3.org/TR/css3-color/#svg-color Installation ============ You don't need to download the GIT version of the code as ``colour`` is available on the PyPI. So you should be able to run:: pip install colour If you have downloaded the GIT sources, then you could add the ``colour.py`` directly to one of your ``site-packages`` (thanks to a symlink). Or install the current version via traditional:: python setup.py install And if you don't have the GIT sources but would like to get the latest master or branch from github, you could also:: pip install git+https://github.com/vaab/colour Or even select a specific revision (branch/tag/commit):: pip install git+https://github.com/vaab/colour@master Usage ===== To get complete demo of each function, please read the source code which is heavily documented and provide a lot of examples in doctest format. Here is a reduced sample of a common usage scenario: Instantiation ------------- Let's create blue color:: >>> from colour import Color >>> c = Color("blue") >>> c Please note that all of these are equivalent examples to create the red color:: Color("red") ## human, web compatible representation Color(red=1) ## default amount of blue and green is 0.0 Color("blue", hue=0) ## hue of blue is 0.66, hue of red is 0.0 Color("#f00") ## standard 3 hex digit web compatible representation Color("#ff0000") ## standard 6 hex digit web compatible representation Color(hue=0, saturation=1, luminance=0.5) Color(hsl=(0, 1, 0.5)) ## full 3-uple HSL specification Color(rgb=(1, 0, 0)) ## full 3-uple RGB specification Color(Color("red")) ## recursion doesn't break object Reading values -------------- Several representations are accessible:: >>> c.hex '#00f' >>> c.hsl # doctest: +ELLIPSIS (0.66..., 1.0, 0.5) >>> c.rgb (0.0, 0.0, 1.0) And their different parts are also independently accessible, as the different amount of red, blue, green, in the RGB format:: >>> c.red 0.0 >>> c.blue 1.0 >>> c.green 0.0 Or the hue, saturation and luminance of the HSL representation:: >>> c.hue # doctest: +ELLIPSIS 0.66... >>> c.saturation 1.0 >>> c.luminance 0.5 A note on the ``.hex`` property, it'll return the smallest valid value when possible. If you are only interested by the long value, use ``.hex_l``:: >>> c.hex_l '#0000ff' Modifying color objects ----------------------- All of these properties are read/write, so let's add some red to this color:: >>> c.red = 1 >>> c We might want to de-saturate this color:: >>> c.saturation = 0.5 >>> c And of course, the string conversion will give the web representation which is human, or 3-digit, or 6-digit hex representation depending which is usable:: >>> "%s" % c '#bf40bf' >>> c.luminance = 1 >>> "%s" % c 'white' Ranges of colors ---------------- You can get some color scale of variation between two ``Color`` objects quite easily. Here, is the color scale of the rainbow between red and blue:: >>> red = Color("red") >>> blue = Color("blue") >>> list(red.range_to(blue, 5)) [, , , , ] Or the different amount of gray between black and white:: >>> black = Color("black") >>> white = Color("white") >>> list(black.range_to(white, 6)) [, , , , , ] If you have to create graphical representation with color scale between red and green ('lime' color is full green):: >>> lime = Color("lime") >>> list(red.range_to(lime, 5)) [, , , , ] Notice how naturally, the yellow is displayed in human format and in the middle of the scale. And that the quite unusual (but compatible) 'chartreuse' color specification has been used in place of the hexadecimal representation. Color comparison ---------------- Sane default ~~~~~~~~~~~~ Color comparison is a vast subject. However, it might seem quite straightforward for you. ``Colour`` uses a configurable default way of comparing color that might suit your needs:: >>> Color("red") == Color("#f00") == Color("blue", hue=0) True The default comparison algorithm focuses only on the "web" representation which is equivalent to comparing the long hex representation (e.g. #FF0000) or to be more specific, it is equivalent to compare the amount of red, green, and blue composition of the RGB representation, each of these value being quantized to a 256 value scale. This default comparison is a practical and convenient way to measure the actual color equivalence on your screen, or in your video card memory. But this comparison wouldn't make the difference between a black red, and a black blue, which both are black:: >>> black_red = Color("red", luminance=0) >>> black_blue = Color("blue", luminance=0) >>> black_red == black_blue True Customization ~~~~~~~~~~~~~ But, this is not the sole way to compare two colors. As I'm quite lazy, I'm providing you a way to customize it to your needs. Thus:: >>> from colour import RGB_equivalence, HSL_equivalence >>> black_red = Color("red", luminance=0, equality=HSL_equivalence) >>> black_blue = Color("blue", luminance=0, equality=HSL_equivalence) >>> black_red == black_blue False As you might have already guessed, the sane default is ``RGB_equivalence``, so:: >>> black_red = Color("red", luminance=0, equality=RGB_equivalence) >>> black_blue = Color("blue", luminance=0, equality=RGB_equivalence) >>> black_red == black_blue True Here's how you could implement your unique comparison function:: >>> saturation_equivalence = lambda c1, c2: c1.saturation == c2.saturation >>> red = Color("red", equality=saturation_equivalence) >>> blue = Color("blue", equality=saturation_equivalence) >>> white = Color("white", equality=saturation_equivalence) >>> red == blue True >>> white == red False Note: When comparing 2 colors, *only* the equality function *of the first color will be used*. Thus:: >>> black_red = Color("red", luminance=0, equality=RGB_equivalence) >>> black_blue = Color("blue", luminance=0, equality=HSL_equivalence) >>> black_red == black_blue True But reverse operation is not equivalent !:: >>> black_blue == black_red False Equality to non-Colour objects ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ As a side note, whatever your custom equality function is, it won't be used if you compare to anything else than a ``Colour`` instance:: >>> red = Color("red", equality=lambda c1, c2: True) >>> blue = Color("blue", equality=lambda c1, c2: True) Note that these instances would compare as equal to any other color:: >>> red == blue True But on another non-Colour object:: >>> red == None False >>> red != None True Actually, ``Colour`` instances will, politely enough, leave the other side of the equality have a chance to decide of the output, (by executing its own ``__eq__``), so:: >>> class OtherColorImplem(object): ... def __init__(self, color): ... self.color = color ... def __eq__(self, other): ... return self.color == other.web >>> alien_red = OtherColorImplem("red") >>> red == alien_red True >>> blue == alien_red False And inequality (using ``__ne__``) are also polite:: >>> class AnotherColorImplem(OtherColorImplem): ... def __ne__(self, other): ... return self.color != other.web >>> new_alien_red = AnotherColorImplem("red") >>> red != new_alien_red False >>> blue != new_alien_red True Picking arbitrary color for a python object ------------------------------------------- Basic Usage ~~~~~~~~~~~ Sometimes, you just want to pick a color for an object in your application often to visually identify this object. Thus, the picked color should be the same for same objects, and different for different object:: >>> foo = object() >>> bar = object() >>> Color(pick_for=foo) # doctest: +ELLIPSIS >>> Color(pick_for=foo) == Color(pick_for=foo) True >>> Color(pick_for=foo) == Color(pick_for=bar) False Of course, although there's a tiny probability that different strings yield the same color, most of the time, different inputs will produce different colors. Advanced Usage ~~~~~~~~~~~~~~ You can customize your color picking algorithm by providing a ``picker``. A ``picker`` is a callable that takes an object, and returns something that can be instantiated as a color by ``Color``:: >>> my_picker = lambda obj: "red" if isinstance(obj, int) else "blue" >>> Color(pick_for=3, picker=my_picker, pick_key=None) >>> Color(pick_for="foo", picker=my_picker, pick_key=None) You might want to use a particular picker, but enforce how the picker will identify two object as the same (or not). So there's a ``pick_key`` attribute that is provided and defaults as equivalent of ``hash`` method and if hash is not supported by your object, it'll default to the ``str`` of your object salted with the class name. Thus:: >>> class MyObj(str): pass >>> my_obj_color = Color(pick_for=MyObj("foo")) >>> my_str_color = Color(pick_for="foo") >>> my_obj_color == my_str_color False Please make sure your object is hashable or "stringable" before using the ``RGB_color_picker`` picking mechanism or provide another color picker. Nearly all python object are hashable by default so this shouldn't be an issue (e.g. instances of ``object`` and subclasses are hashable). Neither ``hash`` nor ``str`` are perfect solution. So feel free to use ``pick_key`` at ``Color`` instantiation time to set your way to identify objects, for instance:: >>> a = object() >>> b = object() >>> Color(pick_for=a, pick_key=id) == Color(pick_for=b, pick_key=id) False When choosing a pick key, you should closely consider if you want your color to be consistent between runs (this is NOT the case with the last example), or consistent with the content of your object if it is a mutable object. Default value of ``pick_key`` and ``picker`` ensures that the same color will be attributed to same object between different run on different computer for most python object. Color factory ------------- As you might have noticed, there are few attributes that you might want to see attached to all of your colors as ``equality`` for equality comparison support, or ``picker``, ``pick_key`` to configure your object color picker. You can create a customized ``Color`` factory thanks to the ``make_color_factory``:: >>> from colour import make_color_factory, HSL_equivalence, RGB_color_picker >>> get_color = make_color_factory( ... equality=HSL_equivalence, ... picker=RGB_color_picker, ... pick_key=str, ... ) All color created thanks to ``CustomColor`` class instead of the default one would get the specified attributes by default:: >>> black_red = get_color("red", luminance=0) >>> black_blue = get_color("blue", luminance=0) Of course, these are always instances of ``Color`` class:: >>> isinstance(black_red, Color) True Equality was changed from normal defaults, so:: >>> black_red == black_blue False This because the default equivalence of ``Color`` was set to ``HSL_equivalence``. Contributing ============ Any suggestion or issue is welcome. Push request are very welcome, please check out the guidelines. Push Request Guidelines ----------------------- You can send any code. I'll look at it and will integrate it myself in the code base and leave you as the author. This process can take time and it'll take less time if you follow the following guidelines: - check your code with PEP8 or pylint. Try to stick to 80 columns wide. - separate your commits per smallest concern. - each commit should pass the tests (to allow easy bisect) - each functionality/bugfix commit should contain the code, tests, and doc. - prior minor commit with typographic or code cosmetic changes are very welcome. These should be tagged in their commit summary with ``!minor``. - the commit message should follow gitchangelog rules (check the git log to get examples) - if the commit fixes an issue or finished the implementation of a feature, please mention it in the summary. If you have some questions about guidelines which is not answered here, please check the current ``git log``, you might find previous commit that would show you how to deal with your issue. License ======= Copyright (c) 2012-2017 Valentin Lab. Licensed under the `BSD License`_. .. _BSD License: http://raw.github.com/vaab/colour/master/LICENSE python-colour-0.1.5/TODO.rst000066400000000000000000000001371322173507300156420ustar00rootroot00000000000000TODO ==== - ANSI 16-color and 256-color escape sequence generation - YUV, HSV, CMYK support python-colour-0.1.5/colour.egg-info/000077500000000000000000000000001322173507300173375ustar00rootroot00000000000000python-colour-0.1.5/colour.egg-info/PKG-INFO000066400000000000000000000550221322173507300204400ustar00rootroot00000000000000Metadata-Version: 1.1 Name: colour Version: 0.1.5 Summary: converts and manipulates various color representation (HSL, RVB, web, X11, ...) Home-page: http://github.com/vaab/colour Author: Valentin LAB Author-email: valentin.lab@kalysto.org License: BSD 3-Clause License Description: ====== Colour ====== .. image:: http://img.shields.io/pypi/v/colour.svg?style=flat :target: https://pypi.python.org/pypi/colour/ :alt: Latest PyPI version .. image:: https://img.shields.io/pypi/l/gitchangelog.svg?style=flat :target: https://github.com/vaab/gitchangelog/blob/master/LICENSE :alt: License .. image:: https://img.shields.io/pypi/pyversions/gitchangelog.svg?style=flat :target: https://pypi.python.org/pypi/gitchangelog/ :alt: Compatible python versions .. image:: http://img.shields.io/pypi/dm/colour.svg?style=flat :target: https://pypi.python.org/pypi/colour/ :alt: Number of PyPI downloads .. image:: http://img.shields.io/travis/vaab/colour/master.svg?style=flat :target: https://travis-ci.org/vaab/colour/ :alt: Travis CI build status .. image:: https://img.shields.io/appveyor/ci/vaab/colour.svg :target: https://ci.appveyor.com/project/vaab/colour/branch/master :alt: Appveyor CI build status .. image:: http://img.shields.io/codecov/c/github/vaab/colour.svg?style=flat :target: https://codecov.io/gh/vaab/colour/ :alt: Test coverage Converts and manipulates common color representation (RGB, HSL, web, ...) Feature ======= - Damn simple and pythonic way to manipulate color representation (see examples below) - Full conversion between RGB, HSL, 6-digit hex, 3-digit hex, human color - One object (``Color``) or bunch of single purpose function (``rgb2hex``, ``hsl2rgb`` ...) - ``web`` format that use the smallest representation between 6-digit (e.g. ``#fa3b2c``), 3-digit (e.g. ``#fbb``), fully spelled color (e.g. ``white``), following `W3C color naming`_ for compatible CSS or HTML color specifications. - smooth intuitive color scale generation choosing N color gradients. - can pick colors for you to identify objects of your application. .. _W3C color naming: http://www.w3.org/TR/css3-color/#svg-color Installation ============ You don't need to download the GIT version of the code as ``colour`` is available on the PyPI. So you should be able to run:: pip install colour If you have downloaded the GIT sources, then you could add the ``colour.py`` directly to one of your ``site-packages`` (thanks to a symlink). Or install the current version via traditional:: python setup.py install And if you don't have the GIT sources but would like to get the latest master or branch from github, you could also:: pip install git+https://github.com/vaab/colour Or even select a specific revision (branch/tag/commit):: pip install git+https://github.com/vaab/colour@master Usage ===== To get complete demo of each function, please read the source code which is heavily documented and provide a lot of examples in doctest format. Here is a reduced sample of a common usage scenario: Instantiation ------------- Let's create blue color:: >>> from colour import Color >>> c = Color("blue") >>> c Please note that all of these are equivalent examples to create the red color:: Color("red") ## human, web compatible representation Color(red=1) ## default amount of blue and green is 0.0 Color("blue", hue=0) ## hue of blue is 0.66, hue of red is 0.0 Color("#f00") ## standard 3 hex digit web compatible representation Color("#ff0000") ## standard 6 hex digit web compatible representation Color(hue=0, saturation=1, luminance=0.5) Color(hsl=(0, 1, 0.5)) ## full 3-uple HSL specification Color(rgb=(1, 0, 0)) ## full 3-uple RGB specification Color(Color("red")) ## recursion doesn't break object Reading values -------------- Several representations are accessible:: >>> c.hex '#00f' >>> c.hsl # doctest: +ELLIPSIS (0.66..., 1.0, 0.5) >>> c.rgb (0.0, 0.0, 1.0) And their different parts are also independently accessible, as the different amount of red, blue, green, in the RGB format:: >>> c.red 0.0 >>> c.blue 1.0 >>> c.green 0.0 Or the hue, saturation and luminance of the HSL representation:: >>> c.hue # doctest: +ELLIPSIS 0.66... >>> c.saturation 1.0 >>> c.luminance 0.5 A note on the ``.hex`` property, it'll return the smallest valid value when possible. If you are only interested by the long value, use ``.hex_l``:: >>> c.hex_l '#0000ff' Modifying color objects ----------------------- All of these properties are read/write, so let's add some red to this color:: >>> c.red = 1 >>> c We might want to de-saturate this color:: >>> c.saturation = 0.5 >>> c And of course, the string conversion will give the web representation which is human, or 3-digit, or 6-digit hex representation depending which is usable:: >>> "%s" % c '#bf40bf' >>> c.luminance = 1 >>> "%s" % c 'white' Ranges of colors ---------------- You can get some color scale of variation between two ``Color`` objects quite easily. Here, is the color scale of the rainbow between red and blue:: >>> red = Color("red") >>> blue = Color("blue") >>> list(red.range_to(blue, 5)) [, , , , ] Or the different amount of gray between black and white:: >>> black = Color("black") >>> white = Color("white") >>> list(black.range_to(white, 6)) [, , , , , ] If you have to create graphical representation with color scale between red and green ('lime' color is full green):: >>> lime = Color("lime") >>> list(red.range_to(lime, 5)) [, , , , ] Notice how naturally, the yellow is displayed in human format and in the middle of the scale. And that the quite unusual (but compatible) 'chartreuse' color specification has been used in place of the hexadecimal representation. Color comparison ---------------- Sane default ~~~~~~~~~~~~ Color comparison is a vast subject. However, it might seem quite straightforward for you. ``Colour`` uses a configurable default way of comparing color that might suit your needs:: >>> Color("red") == Color("#f00") == Color("blue", hue=0) True The default comparison algorithm focuses only on the "web" representation which is equivalent to comparing the long hex representation (e.g. #FF0000) or to be more specific, it is equivalent to compare the amount of red, green, and blue composition of the RGB representation, each of these value being quantized to a 256 value scale. This default comparison is a practical and convenient way to measure the actual color equivalence on your screen, or in your video card memory. But this comparison wouldn't make the difference between a black red, and a black blue, which both are black:: >>> black_red = Color("red", luminance=0) >>> black_blue = Color("blue", luminance=0) >>> black_red == black_blue True Customization ~~~~~~~~~~~~~ But, this is not the sole way to compare two colors. As I'm quite lazy, I'm providing you a way to customize it to your needs. Thus:: >>> from colour import RGB_equivalence, HSL_equivalence >>> black_red = Color("red", luminance=0, equality=HSL_equivalence) >>> black_blue = Color("blue", luminance=0, equality=HSL_equivalence) >>> black_red == black_blue False As you might have already guessed, the sane default is ``RGB_equivalence``, so:: >>> black_red = Color("red", luminance=0, equality=RGB_equivalence) >>> black_blue = Color("blue", luminance=0, equality=RGB_equivalence) >>> black_red == black_blue True Here's how you could implement your unique comparison function:: >>> saturation_equivalence = lambda c1, c2: c1.saturation == c2.saturation >>> red = Color("red", equality=saturation_equivalence) >>> blue = Color("blue", equality=saturation_equivalence) >>> white = Color("white", equality=saturation_equivalence) >>> red == blue True >>> white == red False Note: When comparing 2 colors, *only* the equality function *of the first color will be used*. Thus:: >>> black_red = Color("red", luminance=0, equality=RGB_equivalence) >>> black_blue = Color("blue", luminance=0, equality=HSL_equivalence) >>> black_red == black_blue True But reverse operation is not equivalent !:: >>> black_blue == black_red False Equality to non-Colour objects ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ As a side note, whatever your custom equality function is, it won't be used if you compare to anything else than a ``Colour`` instance:: >>> red = Color("red", equality=lambda c1, c2: True) >>> blue = Color("blue", equality=lambda c1, c2: True) Note that these instances would compare as equal to any other color:: >>> red == blue True But on another non-Colour object:: >>> red == None False >>> red != None True Actually, ``Colour`` instances will, politely enough, leave the other side of the equality have a chance to decide of the output, (by executing its own ``__eq__``), so:: >>> class OtherColorImplem(object): ... def __init__(self, color): ... self.color = color ... def __eq__(self, other): ... return self.color == other.web >>> alien_red = OtherColorImplem("red") >>> red == alien_red True >>> blue == alien_red False And inequality (using ``__ne__``) are also polite:: >>> class AnotherColorImplem(OtherColorImplem): ... def __ne__(self, other): ... return self.color != other.web >>> new_alien_red = AnotherColorImplem("red") >>> red != new_alien_red False >>> blue != new_alien_red True Picking arbitrary color for a python object ------------------------------------------- Basic Usage ~~~~~~~~~~~ Sometimes, you just want to pick a color for an object in your application often to visually identify this object. Thus, the picked color should be the same for same objects, and different for different object:: >>> foo = object() >>> bar = object() >>> Color(pick_for=foo) # doctest: +ELLIPSIS >>> Color(pick_for=foo) == Color(pick_for=foo) True >>> Color(pick_for=foo) == Color(pick_for=bar) False Of course, although there's a tiny probability that different strings yield the same color, most of the time, different inputs will produce different colors. Advanced Usage ~~~~~~~~~~~~~~ You can customize your color picking algorithm by providing a ``picker``. A ``picker`` is a callable that takes an object, and returns something that can be instantiated as a color by ``Color``:: >>> my_picker = lambda obj: "red" if isinstance(obj, int) else "blue" >>> Color(pick_for=3, picker=my_picker, pick_key=None) >>> Color(pick_for="foo", picker=my_picker, pick_key=None) You might want to use a particular picker, but enforce how the picker will identify two object as the same (or not). So there's a ``pick_key`` attribute that is provided and defaults as equivalent of ``hash`` method and if hash is not supported by your object, it'll default to the ``str`` of your object salted with the class name. Thus:: >>> class MyObj(str): pass >>> my_obj_color = Color(pick_for=MyObj("foo")) >>> my_str_color = Color(pick_for="foo") >>> my_obj_color == my_str_color False Please make sure your object is hashable or "stringable" before using the ``RGB_color_picker`` picking mechanism or provide another color picker. Nearly all python object are hashable by default so this shouldn't be an issue (e.g. instances of ``object`` and subclasses are hashable). Neither ``hash`` nor ``str`` are perfect solution. So feel free to use ``pick_key`` at ``Color`` instantiation time to set your way to identify objects, for instance:: >>> a = object() >>> b = object() >>> Color(pick_for=a, pick_key=id) == Color(pick_for=b, pick_key=id) False When choosing a pick key, you should closely consider if you want your color to be consistent between runs (this is NOT the case with the last example), or consistent with the content of your object if it is a mutable object. Default value of ``pick_key`` and ``picker`` ensures that the same color will be attributed to same object between different run on different computer for most python object. Color factory ------------- As you might have noticed, there are few attributes that you might want to see attached to all of your colors as ``equality`` for equality comparison support, or ``picker``, ``pick_key`` to configure your object color picker. You can create a customized ``Color`` factory thanks to the ``make_color_factory``:: >>> from colour import make_color_factory, HSL_equivalence, RGB_color_picker >>> get_color = make_color_factory( ... equality=HSL_equivalence, ... picker=RGB_color_picker, ... pick_key=str, ... ) All color created thanks to ``CustomColor`` class instead of the default one would get the specified attributes by default:: >>> black_red = get_color("red", luminance=0) >>> black_blue = get_color("blue", luminance=0) Of course, these are always instances of ``Color`` class:: >>> isinstance(black_red, Color) True Equality was changed from normal defaults, so:: >>> black_red == black_blue False This because the default equivalence of ``Color`` was set to ``HSL_equivalence``. Contributing ============ Any suggestion or issue is welcome. Push request are very welcome, please check out the guidelines. Push Request Guidelines ----------------------- You can send any code. I'll look at it and will integrate it myself in the code base and leave you as the author. This process can take time and it'll take less time if you follow the following guidelines: - check your code with PEP8 or pylint. Try to stick to 80 columns wide. - separate your commits per smallest concern. - each commit should pass the tests (to allow easy bisect) - each functionality/bugfix commit should contain the code, tests, and doc. - prior minor commit with typographic or code cosmetic changes are very welcome. These should be tagged in their commit summary with ``!minor``. - the commit message should follow gitchangelog rules (check the git log to get examples) - if the commit fixes an issue or finished the implementation of a feature, please mention it in the summary. If you have some questions about guidelines which is not answered here, please check the current ``git log``, you might find previous commit that would show you how to deal with your issue. License ======= Copyright (c) 2012-2017 Valentin Lab. Licensed under the `BSD License`_. .. _BSD License: http://raw.github.com/vaab/colour/master/LICENSE Changelog ========= 0.1.4 (2017-04-19) ------------------ Fix ~~~ - ``rgb2hsl`` would produce invalid hsl triplet when red, blue, green component would be all very close to ``1.0``. (fixes #30) [Valentin Lab] Typically, saturation would shoot out of range 0.0..1.0. That could then lead to exceptions being casts afterwards when trying to reconvert this HSL triplet to RGB values. 0.1.3 (2017-04-08) ------------------ Fix ~~~ - Unexpected behavior with ``!=`` operator. (fixes #26) [Valentin Lab] - Added mention of the ``hex_l`` property. (fixes #27) [Valentin Lab] 0.1.2 (2015-09-15) ------------------ Fix ~~~ - Support for corner case 1-wide ``range_to`` color scale. (fixes #18) [Valentin Lab] 0.1.1 (2015-03-29) ------------------ Fix ~~~ - Avoid casting an exception when comparing to non-``Colour`` instances. (fixes #14) [Riziq Sayegh] 0.0.6 (2014-11-18) ------------------ New ~~~ - Provide all missing *2* function by combination with other existing ones (fixes #13). [Valentin Lab] - Provide full access to any color name in HSL, RGB, HEX convenience instances. [Valentin Lab] Now you can call ``colour.HSL.cyan``, or ``colour.HEX.red`` for a direct encoding of ``human`` colour labels to the 3 representations. 0.0.5 (2013-09-16) ------------------ New ~~~ - Color names are case insensitive. [Chris Priest] The color-name structure have their names capitalized. And color names that are made of only one word will be displayed lowercased. Fix ~~~ - Now using W3C color recommandation. [Chris Priest] Was using X11 color scheme before, which is slightly different from W3C web color specifications. - Inconsistency in licence information (removed GPL mention). (fixes #8) [Valentin Lab] - Removed ``gitchangelog`` from ``setup.py`` require list. (fixes #9) [Valentin Lab] 0.0.4 (2013-06-21) ------------------ New ~~~ - Added ``make_color_factory`` to customize some common color attributes. [Valentin Lab] - Pick color to identify any python object (fixes #6) [Jonathan Ballet] - Equality support between colors, customizable if needed. (fixes #3) [Valentin Lab] 0.0.3 (2013-06-19) ------------------ New ~~~ - Colour is now compatible with python3. [Ryan Leckey] 0.0.1 (2012-06-11) ------------------ - First import. [Valentin Lab] TODO ==== - ANSI 16-color and 256-color escape sequence generation - YUV, HSV, CMYK support Platform: UNKNOWN Classifier: Programming Language :: Python Classifier: Topic :: Software Development :: Libraries :: Python Modules Classifier: Development Status :: 3 - Alpha Classifier: License :: OSI Approved :: BSD License Classifier: Intended Audience :: Developers Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 python-colour-0.1.5/colour.egg-info/SOURCES.txt000066400000000000000000000004041322173507300212210ustar00rootroot00000000000000CHANGELOG.rst LICENSE MANIFEST.in README.rst TODO.rst colour.py setup.cfg setup.py colour.egg-info/PKG-INFO colour.egg-info/SOURCES.txt colour.egg-info/dependency_links.txt colour.egg-info/not-zip-safe colour.egg-info/requires.txt colour.egg-info/top_level.txtpython-colour-0.1.5/colour.egg-info/dependency_links.txt000066400000000000000000000000011322173507300234050ustar00rootroot00000000000000 python-colour-0.1.5/colour.egg-info/not-zip-safe000066400000000000000000000000011322173507300215650ustar00rootroot00000000000000 python-colour-0.1.5/colour.egg-info/requires.txt000066400000000000000000000000151322173507300217330ustar00rootroot00000000000000 [test] nose python-colour-0.1.5/colour.egg-info/top_level.txt000066400000000000000000000000071322173507300220660ustar00rootroot00000000000000colour python-colour-0.1.5/colour.py000066400000000000000000000700251322173507300162230ustar00rootroot00000000000000# -*- coding: utf-8 -*- """Color Library .. :doctest: This module defines several color formats that can be converted to one or another. Formats ------- 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 HEX: string object beginning with '#' and with red, green, blue value. This format accept color in 3 or 6 value ex: '#fff' or '#ffffff' WEB: string object that defaults to HEX representation or human if possible Usage ----- Several function exists to convert from one format to another. But all function are not written. So the best way is to use the object Color. Please see the documentation of this object for more information. .. note:: Some constants are defined for convenience in HSL, RGB, HEX """ from __future__ import with_statement, print_function import hashlib import re import sys ## ## Some Constants ## ## Soften inequalities and some rounding issue based on float FLOAT_ERROR = 0.0000005 RGB_TO_COLOR_NAMES = { (0, 0, 0): ['Black'], (0, 0, 128): ['Navy', 'NavyBlue'], (0, 0, 139): ['DarkBlue'], (0, 0, 205): ['MediumBlue'], (0, 0, 255): ['Blue'], (0, 100, 0): ['DarkGreen'], (0, 128, 0): ['Green'], (0, 139, 139): ['DarkCyan'], (0, 191, 255): ['DeepSkyBlue'], (0, 206, 209): ['DarkTurquoise'], (0, 250, 154): ['MediumSpringGreen'], (0, 255, 0): ['Lime'], (0, 255, 127): ['SpringGreen'], (0, 255, 255): ['Cyan', 'Aqua'], (25, 25, 112): ['MidnightBlue'], (30, 144, 255): ['DodgerBlue'], (32, 178, 170): ['LightSeaGreen'], (34, 139, 34): ['ForestGreen'], (46, 139, 87): ['SeaGreen'], (47, 79, 79): ['DarkSlateGray', 'DarkSlateGrey'], (50, 205, 50): ['LimeGreen'], (60, 179, 113): ['MediumSeaGreen'], (64, 224, 208): ['Turquoise'], (65, 105, 225): ['RoyalBlue'], (70, 130, 180): ['SteelBlue'], (72, 61, 139): ['DarkSlateBlue'], (72, 209, 204): ['MediumTurquoise'], (75, 0, 130): ['Indigo'], (85, 107, 47): ['DarkOliveGreen'], (95, 158, 160): ['CadetBlue'], (100, 149, 237): ['CornflowerBlue'], (102, 205, 170): ['MediumAquamarine'], (105, 105, 105): ['DimGray', 'DimGrey'], (106, 90, 205): ['SlateBlue'], (107, 142, 35): ['OliveDrab'], (112, 128, 144): ['SlateGray', 'SlateGrey'], (119, 136, 153): ['LightSlateGray', 'LightSlateGrey'], (123, 104, 238): ['MediumSlateBlue'], (124, 252, 0): ['LawnGreen'], (127, 255, 0): ['Chartreuse'], (127, 255, 212): ['Aquamarine'], (128, 0, 0): ['Maroon'], (128, 0, 128): ['Purple'], (128, 128, 0): ['Olive'], (128, 128, 128): ['Gray', 'Grey'], (132, 112, 255): ['LightSlateBlue'], (135, 206, 235): ['SkyBlue'], (135, 206, 250): ['LightSkyBlue'], (138, 43, 226): ['BlueViolet'], (139, 0, 0): ['DarkRed'], (139, 0, 139): ['DarkMagenta'], (139, 69, 19): ['SaddleBrown'], (143, 188, 143): ['DarkSeaGreen'], (144, 238, 144): ['LightGreen'], (147, 112, 219): ['MediumPurple'], (148, 0, 211): ['DarkViolet'], (152, 251, 152): ['PaleGreen'], (153, 50, 204): ['DarkOrchid'], (154, 205, 50): ['YellowGreen'], (160, 82, 45): ['Sienna'], (165, 42, 42): ['Brown'], (169, 169, 169): ['DarkGray', 'DarkGrey'], (173, 216, 230): ['LightBlue'], (173, 255, 47): ['GreenYellow'], (175, 238, 238): ['PaleTurquoise'], (176, 196, 222): ['LightSteelBlue'], (176, 224, 230): ['PowderBlue'], (178, 34, 34): ['Firebrick'], (184, 134, 11): ['DarkGoldenrod'], (186, 85, 211): ['MediumOrchid'], (188, 143, 143): ['RosyBrown'], (189, 183, 107): ['DarkKhaki'], (192, 192, 192): ['Silver'], (199, 21, 133): ['MediumVioletRed'], (205, 92, 92): ['IndianRed'], (205, 133, 63): ['Peru'], (208, 32, 144): ['VioletRed'], (210, 105, 30): ['Chocolate'], (210, 180, 140): ['Tan'], (211, 211, 211): ['LightGray', 'LightGrey'], (216, 191, 216): ['Thistle'], (218, 112, 214): ['Orchid'], (218, 165, 32): ['Goldenrod'], (219, 112, 147): ['PaleVioletRed'], (220, 20, 60): ['Crimson'], (220, 220, 220): ['Gainsboro'], (221, 160, 221): ['Plum'], (222, 184, 135): ['Burlywood'], (224, 255, 255): ['LightCyan'], (230, 230, 250): ['Lavender'], (233, 150, 122): ['DarkSalmon'], (238, 130, 238): ['Violet'], (238, 221, 130): ['LightGoldenrod'], (238, 232, 170): ['PaleGoldenrod'], (240, 128, 128): ['LightCoral'], (240, 230, 140): ['Khaki'], (240, 248, 255): ['AliceBlue'], (240, 255, 240): ['Honeydew'], (240, 255, 255): ['Azure'], (244, 164, 96): ['SandyBrown'], (245, 222, 179): ['Wheat'], (245, 245, 220): ['Beige'], (245, 245, 245): ['WhiteSmoke'], (245, 255, 250): ['MintCream'], (248, 248, 255): ['GhostWhite'], (250, 128, 114): ['Salmon'], (250, 235, 215): ['AntiqueWhite'], (250, 240, 230): ['Linen'], (250, 250, 210): ['LightGoldenrodYellow'], (253, 245, 230): ['OldLace'], (255, 0, 0): ['Red'], (255, 0, 255): ['Magenta', 'Fuchsia'], (255, 20, 147): ['DeepPink'], (255, 69, 0): ['OrangeRed'], (255, 99, 71): ['Tomato'], (255, 105, 180): ['HotPink'], (255, 127, 80): ['Coral'], (255, 140, 0): ['DarkOrange'], (255, 160, 122): ['LightSalmon'], (255, 165, 0): ['Orange'], (255, 182, 193): ['LightPink'], (255, 192, 203): ['Pink'], (255, 215, 0): ['Gold'], (255, 218, 185): ['PeachPuff'], (255, 222, 173): ['NavajoWhite'], (255, 228, 181): ['Moccasin'], (255, 228, 196): ['Bisque'], (255, 228, 225): ['MistyRose'], (255, 235, 205): ['BlanchedAlmond'], (255, 239, 213): ['PapayaWhip'], (255, 240, 245): ['LavenderBlush'], (255, 245, 238): ['Seashell'], (255, 248, 220): ['Cornsilk'], (255, 250, 205): ['LemonChiffon'], (255, 250, 240): ['FloralWhite'], (255, 250, 250): ['Snow'], (255, 255, 0): ['Yellow'], (255, 255, 224): ['LightYellow'], (255, 255, 240): ['Ivory'], (255, 255, 255): ['White'] } ## Building inverse relation COLOR_NAME_TO_RGB = dict( (name.lower(), rgb) for rgb, names in RGB_TO_COLOR_NAMES.items() for name in names) LONG_HEX_COLOR = re.compile(r'^#[0-9a-fA-F]{6}$') SHORT_HEX_COLOR = re.compile(r'^#[0-9a-fA-F]{3}$') 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)) HSL = C_HSL() class C_RGB: """RGB colors container Provides a quick color access. >>> from colour import RGB >>> RGB.WHITE (1.0, 1.0, 1.0) >>> RGB.BLUE (0.0, 0.0, 1.0) >>> RGB.DONOTEXISTS # doctest: +ELLIPSIS Traceback (most recent call last): ... AttributeError: ... has no attribute 'DONOTEXISTS' """ def __getattr__(self, value): return hsl2rgb(getattr(HSL, value)) class C_HEX: """RGB colors container Provides a quick color access. >>> from colour import HEX >>> HEX.WHITE '#fff' >>> HEX.BLUE '#00f' >>> HEX.DONOTEXISTS # doctest: +ELLIPSIS Traceback (most recent call last): ... AttributeError: ... has no attribute 'DONOTEXISTS' """ def __getattr__(self, value): return rgb2hex(getattr(RGB, value)) RGB = C_RGB() HEX = C_HEX() ## ## Conversion function ## 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 conversion: >>> 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 rgb2hsl(rgb): """Convert RGB representation towards HSL :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 HSL values in float between 0 and 1 This algorithm came from: http://www.easyrgb.com/index.php?X=MATH&H=19#text19 Here are some quick notion of RGB to HSL conversion: >>> from colour import rgb2hsl Note that if red amount is equal to green and blue, then you should have a gray value (from black to white). >>> rgb2hsl((1.0, 1.0, 1.0)) # doctest: +ELLIPSIS (..., 0.0, 1.0) >>> rgb2hsl((0.5, 0.5, 0.5)) # doctest: +ELLIPSIS (..., 0.0, 0.5) >>> rgb2hsl((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: >>> rgb2hsl((0.5, 0.5, 1.0)) # doctest: +ELLIPSIS (0.66..., 1.0, 0.75) >>> rgb2hsl((0.2, 0.1, 0.1)) # doctest: +ELLIPSIS (0.0, 0.33..., 0.15...) Having only one value set, you can check that: >>> rgb2hsl((1.0, 0.0, 0.0)) (0.0, 1.0, 0.5) >>> rgb2hsl((0.0, 1.0, 0.0)) # doctest: +ELLIPSIS (0.33..., 1.0, 0.5) >>> rgb2hsl((0.0, 0.0, 1.0)) # doctest: +ELLIPSIS (0.66..., 1.0, 0.5) Regression check upon very close values in every component of red, green and blue: >>> rgb2hsl((0.9999999999999999, 1.0, 0.9999999999999994)) (0.0, 0.0, 0.999...) Of course: >>> rgb2hsl((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: >>> rgb2hsl((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. """ 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)) 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 < FLOAT_ERROR: ## This is a gray, no chroma... return (0.0, 0.0, l) ## ## Chromatic data... ## ## Saturation if l < 0.5: s = diff / vsum else: s = diff / (2.0 - vsum) 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 if h < 0: h += 1 if h > 1: h -= 1 return (h, s, l) 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 not force_long and hx[0::2] == hx[1::2]: hx = ''.join(hx[0::2]) return "#%s" % hx def hex2rgb(str_rgb): """Transform hex RGB representation to RGB tuple :param str_rgb: 3 hex char or 6 hex char string representation :rtype: RGB 3-uple of float between 0 and 1 >>> from colour import hex2rgb >>> hex2rgb('#00ff00') (0.0, 1.0, 0.0) >>> hex2rgb('#0f0') (0.0, 1.0, 0.0) >>> hex2rgb('#aaa') # doctest: +ELLIPSIS (0.66..., 0.66..., 0.66...) >>> hex2rgb('#aa') # doctest: +ELLIPSIS Traceback (most recent call last): ... ValueError: Invalid value '#aa' provided for rgb color. """ try: rgb = str_rgb[1:] if len(rgb) == 6: r, g, b = rgb[0:2], rgb[2:4], rgb[4:6] elif len(rgb) == 3: r, g, b = rgb[0] * 2, rgb[1] * 2, rgb[2] * 2 else: raise ValueError() except: raise ValueError("Invalid value %r provided for rgb color." % 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 conversion 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 conversion 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) ## Missing functions conversion hsl2hex = lambda x: rgb2hex(hsl2rgb(x)) hex2hsl = lambda x: rgb2hsl(hex2rgb(x)) rgb2web = lambda x: hex2web(rgb2hex(x)) web2rgb = lambda x: hex2rgb(web2hex(x)) web2hsl = lambda x: rgb2hsl(web2rgb(x)) hsl2web = lambda x: rgb2web(hsl2rgb(x)) def color_scale(begin_hsl, end_hsl, nb): """Returns a list of nb color HSL tuples between begin_hsl and end_hsl >>> from colour import color_scale >>> [rgb2hex(hsl2rgb(hsl)) for hsl in color_scale((0, 1, 0.5), ... (1, 1, 0.5), 3)] ['#f00', '#0f0', '#00f', '#f00'] >>> [rgb2hex(hsl2rgb(hsl)) ... for hsl in color_scale((0, 0, 0), ... (0, 0, 1), ... 15)] # doctest: +ELLIPSIS ['#000', '#111', '#222', ..., '#ccc', '#ddd', '#eee', '#fff'] Of course, asking for negative values is not supported: >>> color_scale((0, 1, 0.5), (1, 1, 0.5), -2) Traceback (most recent call last): ... ValueError: Unsupported negative number of colors (nb=-2). """ if nb < 0: raise ValueError( "Unsupported negative number of colors (nb=%r)." % nb) step = tuple([float(end_hsl[i] - begin_hsl[i]) / nb for i in range(0, 3)]) \ if nb > 0 else (0, 0, 0) def mul(step, value): return tuple([v * value for v in step]) def add_v(step, step2): return tuple([v + step2[i] for i, v in enumerate(step)]) return [add_v(begin_hsl, mul(step, r)) for r in range(0, nb + 1)] ## ## Color Pickers ## def RGB_color_picker(obj): """Build a color representation from the string representation of an object This allows to quickly get a color from some data, with the additional benefit that the color will be the same as long as the (string representation of the) data is the same:: >>> from colour import RGB_color_picker, Color Same inputs produce the same result:: >>> RGB_color_picker("Something") == RGB_color_picker("Something") True ... but different inputs produce different colors:: >>> RGB_color_picker("Something") != RGB_color_picker("Something else") True In any case, we still get a ``Color`` object:: >>> isinstance(RGB_color_picker("Something"), Color) True """ ## Turn the input into a by 3-dividable string. SHA-384 is good because it ## divides into 3 components of the same size, which will be used to ## represent the RGB values of the color. digest = hashlib.sha384(str(obj).encode('utf-8')).hexdigest() ## Split the digest into 3 sub-strings of equivalent size. subsize = int(len(digest) / 3) splitted_digest = [digest[i * subsize: (i + 1) * subsize] for i in range(3)] ## Convert those hexadecimal sub-strings into integer and scale them down ## to the 0..1 range. max_value = float(int("f" * subsize, 16)) components = ( int(d, 16) ## Make a number from a list with hex digits / max_value ## Scale it down to [0.0, 1.0] for d in splitted_digest) return Color(rgb2hex(components)) ## Profit! def hash_or_str(obj): try: return hash((type(obj).__name__, obj)) except TypeError: ## Adds the type name to make sure two object of different type but ## identical string representation get distinguished. return type(obj).__name__ + str(obj) ## ## All purpose object ## 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. >>> from colour import Color, HSL >>> b = Color() >>> b.hsl = HSL.BLUE Access values ------------- >>> b.hue # doctest: +ELLIPSIS 0.66... >>> b.saturation 1.0 >>> b.luminance 0.5 >>> b.red 0.0 >>> b.blue 1.0 >>> b.green 0.0 >>> b.rgb (0.0, 0.0, 1.0) >>> b.hsl # doctest: +ELLIPSIS (0.66..., 1.0, 0.5) >>> b.hex '#00f' Change values ------------- Let's change Hue toward red tint: >>> b.hue = 0.0 >>> b.hex '#f00' >>> b.hue = 2.0/3 >>> b.hex '#00f' In the other way round: >>> b.hex = '#f00' >>> b.hsl (0.0, 1.0, 0.5) Long hex can be accessed directly: >>> b.hex_l = '#123456' >>> b.hex_l '#123456' >>> b.hex '#123456' >>> b.hex_l = '#ff0000' >>> b.hex_l '#ff0000' >>> b.hex '#f00' Convenience ----------- >>> c = Color('blue') >>> c >>> c.hue = 0 >>> c >>> c.saturation = 0.0 >>> c.hsl # doctest: +ELLIPSIS (..., 0.0, 0.5) >>> c.rgb (0.5, 0.5, 0.5) >>> c.hex '#7f7f7f' >>> c >>> c.luminance = 0.0 >>> c >>> c.hex '#000' >>> c.green = 1.0 >>> c.blue = 1.0 >>> c.hex '#0ff' >>> c >>> c = Color('blue', luminance=0.75) >>> c >>> c = Color('red', red=0.5) >>> c >>> print(c) #7f0000 You can try to query unexisting attributes: >>> c.lightness # doctest: +ELLIPSIS Traceback (most recent call last): ... AttributeError: 'lightness' not found TODO: could add HSV, CMYK, YUV conversion. # >>> b.hsv # >>> b.value # >>> b.cyan # >>> b.magenta # >>> b.yellow # >>> b.key # >>> b.cmyk Recursive init -------------- To support blind conversion of web strings (or already converted object), the Color object supports instantiation with another Color object. >>> Color(Color(Color('red'))) Equality support ---------------- Default equality is RGB hex comparison: >>> Color('red') == Color('blue') False >>> Color('red') == Color('red') True >>> Color('red') != Color('blue') True >>> Color('red') != Color('red') False But this can be changed: >>> saturation_equality = lambda c1, c2: c1.luminance == c2.luminance >>> Color('red', equality=saturation_equality) == Color('blue') True Subclassing support ------------------- You should be able to subclass ``Color`` object without any issues:: >>> class Tint(Color): ... pass And keep the internal API working:: >>> Tint("red").hsl (0.0, 1.0, 0.5) """ _hsl = None ## internal representation def __init__(self, color=None, pick_for=None, picker=RGB_color_picker, pick_key=hash_or_str, **kwargs): if pick_key is None: pick_key = lambda x: x if pick_for is not None: color = picker(pick_key(pick_for)) if isinstance(color, Color): self.web = color.web else: self.web = color if color else 'black' self.equality = RGB_equivalence for k, v in kwargs.items(): setattr(self, k, v) def __getattr__(self, label): if label.startswith("get_"): raise AttributeError("'%s' not found" % label) try: return getattr(self, 'get_' + label)() except AttributeError: raise AttributeError("'%s' not found" % label) def __setattr__(self, label, value): if label not in ["_hsl", "equality"]: fc = getattr(self, 'set_' + label) fc(value) else: self.__dict__[label] = value ## ## Get ## def get_hsl(self): return tuple(self._hsl) def get_hex(self): return rgb2hex(self.rgb) def get_hex_l(self): return rgb2hex(self.rgb, force_long=True) def get_rgb(self): return hsl2rgb(self.hsl) def get_hue(self): return self.hsl[0] def get_saturation(self): return self.hsl[1] def get_luminance(self): return self.hsl[2] def get_red(self): return self.rgb[0] def get_green(self): return self.rgb[1] def get_blue(self): return self.rgb[2] def get_web(self): return hex2web(self.hex) ## ## Set ## def set_hsl(self, value): self._hsl = list(value) def set_rgb(self, value): self.hsl = rgb2hsl(value) def set_hue(self, value): self._hsl[0] = value def set_saturation(self, value): self._hsl[1] = value def set_luminance(self, value): self._hsl[2] = value def set_red(self, value): _, g, b = self.rgb self.rgb = (value, g, b) def set_green(self, value): r, _, b = self.rgb self.rgb = (r, value, b) def set_blue(self, value): r, g, _ = self.rgb self.rgb = (r, g, value) def set_hex(self, value): self.rgb = hex2rgb(value) set_hex_l = set_hex def set_web(self, value): self.hex = web2hex(value) ## range of color generation def range_to(self, value, steps): for hsl in color_scale(self._hsl, Color(value).hsl, steps - 1): yield Color(hsl=hsl) ## ## Convenience ## def __str__(self): return "%s" % self.web def __repr__(self): return "" % self.web def __eq__(self, other): if isinstance(other, Color): return self.equality(self, other) return NotImplemented if sys.version_info[0] == 2: ## Note: intended to be a backport of python 3 behavior def __ne__(self, other): equal = self.__eq__(other) return equal if equal is NotImplemented else not equal RGB_equivalence = lambda c1, c2: c1.hex_l == c2.hex_l HSL_equivalence = lambda c1, c2: c1._hsl == c2._hsl def make_color_factory(**kwargs_defaults): def ColorFactory(*args, **kwargs): new_kwargs = kwargs_defaults.copy() new_kwargs.update(kwargs) return Color(*args, **new_kwargs) return ColorFactory python-colour-0.1.5/setup.cfg000066400000000000000000000023451322173507300161670ustar00rootroot00000000000000[metadata] name = colour version = 0.1.5 summary = converts and manipulates various color representation (HSL, RVB, web, X11, ...) description-file = README.rst CHANGELOG.rst TODO.rst license_file = LICENSE requires-dist = author = Valentin LAB author_email = valentin.lab@kalysto.org home_page = http://github.com/vaab/colour license = BSD 3-Clause License classifier = Programming Language :: Python Topic :: Software Development :: Libraries :: Python Modules Development Status :: 3 - Alpha License :: OSI Approved :: BSD License Intended Audience :: Developers Programming Language :: Python :: 2 Programming Language :: Python :: 2.7 Programming Language :: Python :: 3 Programming Language :: Python :: 3.3 Programming Language :: Python :: 3.4 Programming Language :: Python :: 3.5 Programming Language :: Python :: 3.6 [files] modules = colour extra_files = README.rst CHANGELOG.rst TODO.rst setup.py [backwards_compat] zip-safe = False [bdist_wheel] universal = 1 [nosetests] verbosity = 3 with-doctest = 1 doctest-extension = rst exe = 1 with-coverage = 1 cover-package = colour cover-min-percentage = 90 doctest-options = +ELLIPSIS,+NORMALIZE_WHITESPACE [egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 python-colour-0.1.5/setup.py000066400000000000000000000036711322173507300160630ustar00rootroot00000000000000#!/usr/bin/env python ## ## You can download latest version of this file: ## $ wget https://gist.github.com/vaab/e0eae9607ae806b662d4/raw -O setup.py ## $ chmod +x setup.py ## ## This setup.py is meant to be run along with ``./autogen.sh`` that ## you can also find here: https://gist.github.com/vaab/9118087/raw ## try: from setuptools import setup except ImportError: from distribute_setup import use_setuptools use_setuptools() from setuptools import setup ## ## Ensure that ``./autogen.sh`` is run prior to using ``setup.py`` ## if "0.1.5".startswith("%%"): import os.path import sys WIN32 = sys.platform == 'win32' autogen = os.path.join(".", "autogen.sh") if not os.path.exists(autogen): sys.stderr.write( "This source repository was not configured.\n" "Please ensure ``./autogen.sh`` exists and that you are running " "``setup.py`` from the project root directory.\n") sys.exit(1) if os.path.exists('.autogen.sh.output'): sys.stderr.write( "It seems that ``./autogen.sh`` couldn't do its job as expected.\n" "Please try to launch ``./autogen.sh`` manualy, and send the " "results to the\nmaintainer of this package.\n" "Package will not be installed !\n") sys.exit(1) sys.stderr.write("Missing version information: " "running './autogen.sh'...\n") import os import subprocess os.system('%s%s > .autogen.sh.output' % ("bash " if WIN32 else "", autogen)) cmdline = sys.argv[:] if cmdline[0] == "-c": ## for some reason, this is needed when launched from pip cmdline[0] = "setup.py" errlvl = subprocess.call(["python", ] + cmdline) os.unlink(".autogen.sh.output") sys.exit(errlvl) ## ## Normal d2to1 setup ## setup( setup_requires=['d2to1'], extras_require={'test': ['nose', ]}, d2to1=True )