1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
|
.. The colorzero color library
..
.. Copyright (c) 2016-2021 Dave Jones <dave@waveform.org.uk>
..
.. SPDX-License-Identifier: BSD-3-Clause
===============
Getting started
===============
.. currentmodule:: colorzero
The :class:`Color` class is the main interface provided by colorzero. It can be
constructed in a large variety of ways including with red, green, and blue
components, "well known" color names (taken from CSS 3's `extended color
keywords`_), HTML color specifications, and more. A selection of valid
constructors is shown below:
.. code-block:: pycon
>>> from colorzero import *
>>> Color('red')
<Color html="#ff0000" rgb=(1.0, 0.0, 0.0)>
>>> Color(1.0, 0.0, 0.0)
<Color html="#ff0000" rgb=(1.0, 0.0, 0.0)>
>>> Color(255, 0, 0)
<Color html="#ff0000" rgb=(1.0, 0.0, 0.0)>
>>> Color('#ff0000')
<Color html="#ff0000" rgb=(1.0, 0.0, 0.0)>
>>> Color('#f00')
<Color html="#ff0000" rgb=(1.0, 0.0, 0.0)>
Internally, colorzero always represents colors as red, green, and blue values
between 0.0 and 1.0. :class:`Color` objects are tuple descendents. Crucially,
this means they are *immutable*. Attempting to change the red, green, or blue
attributes will fail:
.. code-block:: pycon
>>> c = Color('red')
>>> c.red
Red(1.0)
>>> c.red = 0.5
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: can't set attribute
In order to manipulate a color, colorzero provides a simple series of classes
which represent attributes of a color: :class:`Red`, :class:`Green`,
:class:`Blue`, :class:`Hue`, :class:`Lightness`, :class:`Saturation` and so on.
You can use these classes in combination with Python's usual mathematical
operators (addition, subtraction, multiplication, etc.) to manipulate a color.
For example, continuing the example from above:
.. code-block:: pycon
>>> c + Green(0.1)
<Color html='#ff1a00' rgb=(1, 0.1, 0)>
>>> c = c + Green(0.5)
>>> c
<Color html='#ff8000' rgb=(1, 0.5, 0)>
>>> c.lightness
Lightness(0.5)
>>> c = c * Lightness(0.5)
>>> c
<Color html='#804000' rgb=(0.5, 0.25, 0)>
Numerous attributes are provided to enable conversion of the RGB representation
to other systems:
.. code-block:: pycon
>>> c.rgb
RGB(r=0.5, g=0.25, b=0.0)
>>> c.rgb_bytes
RGB(r=128, g=64, b=0)
>>> c.rgb565
31200
>>> c.hls
HLS(h=0.08333333333333333, l=0.25, s=1.0)
>>> c.xyz
XYZ(x=0.10647471144683732, y=0.0819048964489466, z=0.010202272707313633)
>>> c.lab
Lab(l=34.376494620040376, a=23.890819210881016, b=44.69197916172735)
Equivalent constructors exist for all these systems:
.. code-block:: pycon
>>> Color.from_rgb(0.5, 0.25, 0.0)
<Color html='#804000' rgb=(0.5, 0.25, 0)>
>>> Color.from_rgb_bytes(128, 64, 0)
<Color html='#804000' rgb=(0.501961, 0.25098, 0)>
>>> Color.from_rgb565(31200)
<Color html='#7b3d00' rgb=(0.483871, 0.238095, 0)>
>>> Color.from_hls(*c.hls)
<Color html='#804000' rgb=(0.5, 0.25, 0)>
>>> Color.from_xyz(*c.xyz)
<Color html='#7f4000' rgb=(0.5, 0.25, 0)>
>>> Color.from_lab(*c.lab)
<Color html='#7f4000' rgb=(0.5, 0.25, 0)>
Note that some conversions lose a certain amount of precision.
The :func:`repr` output of :class:`Color` is relatively verbose by default, but
this can be customized via the :class:`Color.repr_style` class attribute:
.. code-block:: pycon
>>> c = Color('red')
>>> c
<Color html="#ff0000" rgb=(1.0, 0.0, 0.0)>
>>> Color.repr_style = 'html'
>>> c
Color('#ff0000')
>>> Color.repr_style = 'rgb'
>>> c
Color(1, 0, 0)
If you have a terminal capable of color output (usually this means an actual
terminal, not those integrated into applications like IDLE, Thonny, etc.), you
can also preview colors with this facility (the output below shows the ANSI
codes produced, but the documentation system won't reproduce the colored
output):
.. code-block:: pycon
>>> Color.repr_style = 'term256'
>>> c
<Color ### rgb=(1, 0, 0)>
>>> repr(c)
'<Color \x1b[38;5;9m###\x1b[0m rgb=(1, 0, 0)>'
>>> Color.repr_style = 'term16m'
>>> c
<Color ### rgb=(1, 0, 0)>
>>> repr(c)
'<Color \x1b[38;2;255;0;0m###\x1b[0m rgb=(1, 0, 0)>'
These ANSI codes can also be generated by using colors with :meth:`str.format`.
For example:
.. code-block:: pycon
>>> '{c:16m}Red{c:0} Alert!'.format(c=Color('red'))
'\x1b[38;2;255;0;0mRed\x1b[0m Alert!'
See :ref:`format` for more information.
A method (:meth:`~Color.gradient`) is provided to generate gradients which fade
from one color to another. The result is a generator, which must be iterated
over if you want all the results:
.. code-block:: pycon
>>> Color.repr_style = 'term16m'
>>> for c in Color('red').gradient(Color('green')):
... print(repr(c))
...
<Color ### rgb=(1, 0, 0)>
<Color ### rgb=(0.888889, 0.0557734, 0)>
<Color ### rgb=(0.777778, 0.111547, 0)>
<Color ### rgb=(0.666667, 0.16732, 0)>
<Color ### rgb=(0.555556, 0.223094, 0)>
<Color ### rgb=(0.444444, 0.278867, 0)>
<Color ### rgb=(0.333333, 0.334641, 0)>
<Color ### rgb=(0.222222, 0.390414, 0)>
<Color ### rgb=(0.111111, 0.446187, 0)>
<Color ### rgb=(0, 0.501961, 0)>
In a color-capable terminal, the "###" above will appear to fade between the
two specified colors.
Methods are also provided to compare colors for similarity. The simplest
algorithm (and the default) is "euclid" which calculates the difference as the
distance between them by treating the r, g, b components as coordinates in a
3-dimensional space. The same color will have a distance of 0.0, whilst the
largest possible difference is :math:`\sqrt{3}` (:math:`\approx 1.732`):
.. code-block:: pycon
>>> c1 = Color('red')
>>> c2 = Color('green')
>>> c3 = c1 * Lightness(0.9)
>>> c1.difference(c2, 'euclid')
1.1189122525867927
>>> c1.difference(c2)
1.1189122525867927
>>> c1.difference(c3)
0.09999999999999998
Various `Delta-E`_ algorithms (CIE1976, CIE1994, and CIEDE2000) are also
provided. In these systems, 2.3 is considered a "just noticeable difference":
.. code-block:: pycon
>>> c1.difference(c2, 'cie1976')
133.10729836196307
>>> c1.difference(c3, 'cie1976')
9.60280542204272
>>> c1.difference(c2, 'cie1994g')
50.97596644678241
>>> c1.difference(c3, 'cie1994g')
5.484832836355026
>>> c1.difference(c2, 'ciede2000')
72.18229138962074
>>> c1.difference(c3, 'ciede2000')
5.490813507834904
These algorithms are also available as straight-forward functions:
.. code-block:: pycon
>>> cie1976(c1, c2)
133.10729836196307
>>> ciede2000(c1, c3)
5.490813507834904
.. _extended color keywords: https://www.w3.org/TR/css3-color/#svg-color
.. _Delta-E: https://en.wikipedia.org/wiki/Color_difference
|