colorzero¶
colorzero is a color manipulation library for Python (yes, another one) which aims to be reasonably simple to use and “pythonic” in nature.
It does not aim to be as comprehensive, powerful, or that matter as correct as, say, colormath. colorzero originally grew out of work on my picamera project, hence it’s intended to be sufficiently simple that school children can use it without having to explain color spaces and illuminants. However, it does aim to be useful to a wide range of skills, hence it does include basic facilities for CIE Lab representations, and Delta-E calculations should you need them.
The major difference between colorzero and other libraries (grapefruit,
colormath, etc.) is that its Color
class is a namedtuple
descendent.
This means it is immutable; you cannot directly change the attributes of a
Color
instance. The major advantage of this is that instances can be used
as keys in dictionaries (for simple LUTs), or placed in sets.
Manipulation of Color
instances is done by typical operations with other
classes the result of which is a new Color
instance. For example:
>>> Color('red') + Color('blue')
<Color html='#ff00ff' rgb=(1, 0, 1)>
>>> Color('magenta') - Color('red')
<Color html='#0000ff' rgb=(0, 0, 1)>
>>> Color('red') - Red(0.5)
<Color html='#800000' rgb=(0.5, 0, 0)>
>>> Color('green') + Color('grey').red
<Color html='#808000' rgb=(0.501961, 0.501961, 0)>
>>> Color.from_hls(0.5, 0.5, 1.0)
<Color html='#00ffff' rgb=(0, 1, 1)>
>>> Color.from_hls(0.5, 0.5, 1.0) * Lightness(0.8)
<Color html='#00cccc' rgb=(0, 0.8, 0.8)>
>>> (Color.from_hls(0.5, 0.5, 1.0) * Lightness(0.8)).hls
HLS(h=0.5, l=0.4, s=1.0)
Links¶
- The code is licensed under the BSD license
- The source code can be obtained from GitHub, which also hosts the bug tracker
- The documentation (which includes installation, quick-start examples, and lots of code recipes) can be read on ReadTheDocs
- Packages can be downloaded from PyPI, but reading the installation instructions is more likely to be useful
Table of Contents¶
Installation¶
Raspbian installation¶
On Raspbian, it is best to obtain colorzero via the apt
utility:
$ sudo apt update
$ sudo apt install python-colorzero python3-colorzero
The usual apt upgrade method can be used to keep your installation up to date:
$ sudo apt update
$ sudo apt upgrade
To remove your installation:
$ sudo apt remove python-colorzero python3-colorzero
Ubuntu installation¶
If you are using Ubuntu, it is probably easiest to obtain colorzero from the author’s PPA:
$ sudo add-apt-repository ppa://waveform/ppa
$ sudo apt update
$ sudo apt install python-colorzero python3-colorzero
The usual apt upgrade method can be used to keep your installation up to date:
$ sudo apt update
$ sudo apt upgrade
To remove your installation:
$ sudo apt remove python-colorzero python3-colorzero
Other platforms¶
On other platforms, it is probably easiest to obtain colorzero via the pip
utility:
$ sudo pip install colorzero
$ sudo pip3 install colorzero
To upgrade your installation:
$ sudo pip install -U colorzero
$ sudo pip3 install -U colorzero
To remove your installation:
$ sudo pip remove colorzero
$ sudo pip3 remove colorzero
Getting started¶
The 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:
>>> 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. Color
objects are tuple descendents. Crucially,
this means they are immutable. Attempting to change the red, green, or blue
attributes will fail:
>>> 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: Red
, Green
,
Blue
, Hue
, Lightness
, 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:
>>> 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:
>>> 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:
>>> 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 repr()
output of Color
is relatively verbose by default, but
this can be customized via the Color.repr_style
class attribute:
>>> 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):
>>> 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 str.format()
.
For example:
>>> '{c:16m}Red{c:0} Alert!'.format(c=Color('red'))
'\x1b[38;2;255;0;0mRed\x1b[0m Alert!'
See Format Strings for more information.
A method (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:
>>> 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 √3 (≈1.732):
>>> 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”:
>>> 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:
>>> cie1976(c1, c2)
133.10729836196307
>>> ciede2000(c1, c3)
5.490813507834904
API¶
The colorzero library includes a comprehensive Color
class which
is capable of converting between numerous color representations and calculating
color differences. Various ancillary classes can be used to manipulate aspects
of a color.
Color Class¶
This the primary class in the package, and often the only class you’ll need or want to interact with. It has an extremely flexible constructor, along with numerous explicit constructors, and attributes for conversion to other color systems.
-
class
colorzero.
Color
[source]¶ The Color class is a tuple which represents a color as linear red, green, and blue components.
The class has a flexible constructor which allows you to create an instance from any built-in color system. There are also explicit constructors for every known system that can convert (directly or indirectly) to linear RGB. For example, an instance of
Color
can be constructed in any of the following ways:>>> Color('#f00') <Color html='#ff0000' rgb=(1, 0, 0)> >>> Color('green') <Color html='#008000' rgb=(0.0, 0.501961, 0.0)> >>> Color(0, 0, 1) <Color html='#0000ff' rgb=(0, 0, 1)> >>> Color(h=0, s=1, v=0.5) <Color html='#800000' rgb=(0.5, 0, 0)> >>> Color(y=0.4, u=-0.05, v=0.615) <Color html='#ff104c' rgb=(1, 0.0626644, 0.298394)>
The specific forms that the default constructor will accept are enumerated below:
Style Description Single scalar parameter Equivalent to calling Color.from_string()
, orColor.from_rgb24()
.Three positional parameters or a 3-tuple with no field names Equivalent to calling Color.from_rgb()
if all three parameters are between 0.0 and 1.0, orColor.from_rgb_bytes()
otherwise.Three named parameters, or a 3-tuple with fields “r”, “g”, “b” Three named parameters, or a 3-tuple with fields “red”, “green”, “blue” Three named parameters, or a 3-tuple with fields “y”, “u”, “v” Equivalent to calling Color.from_yuv()
if “y” is between 0.0 and 1.0, “u” is between -0.436 and 0.436, and “v” is between -0.615 and 0.615, orColor.from_yuv_bytes()
otherwise.Three named parameters, or a 3-tuple with fields “y”, “i”, “q” Equivalent to calling Color.from_yiq()
.Three named parameters, or a 3-tuple with fields “h”, “l”, “s” Equivalent to calling Color.from_hls()
.Three named parameters, or a 3-tuple with fields “hue”, “lightness”, “saturation” Three named parameters, or a 3-tuple with fields “h”, “s”, “v” Equivalent to calling Color.from_hsv()
Three named parameters, or a 3-tuple with fields “hue”, “saturation”, “value” Three named parameters, or a 3-tuple with fields “x”, “y”, “z” Equivalent to calling Color.from_xyz()
Three named parameters, or a 3-tuple with fields “l”, “a”, “b” Equivalent to calling Color.from_lab()
Three named parameters, or a 3-tuple with fields “l”, “u”, “v” Equivalent to calling Color.from_luv()
If the constructor parameters do not conform to any of the variants in the table above, a
ValueError
will be raised.Internally, the color is always represented as 3
float
values corresponding to the red, green, and blue components of the color. These values take a value from 0.0 to 1.0 (least to full intensity). The class provides several attributes which can be used to convert one color system into another:>>> Color('#f00').hls HLS(h=0.0, l=0.5, s=1.0) >>> Color.from_string('green').hue Hue(deg=120.0) >>> Color.from_rgb_bytes(0, 0, 255).yuv YUV(y=0.114, u=0.436, v=-0.10001426533523537)
As
Color
derives from tuple, instances are immutable. While this provides the advantage that they can be used in aset
or as keys of adict
, it does mean that colors themselves cannot be directly manipulated (e.g. by setting the red component).However, several auxilliary classes in the module provide the ability to perform simple transformations of colors via operators which produce a new
Color
instance. For example, you can add, subtract, and multiply colors directly:>>> Color('red') + Color('blue') <Color html='#ff00ff' rgb=(1, 0, 1)> >>> Color('magenta') - Color('red') <Color html='#0000ff' rgb=(0, 0, 1)>
Values are clipped to ensure the resulting color is still valid:
>>> Color('#ff00ff') + Color('#ff0000') <Color html='#ff00ff' rgb=(1, 0, 1)>
You can wrap numbers in constructors like
Red
(or obtain elements of existing colors), then add, subtract, or multiply them with aColor
:>>> Color('red') - Red(0.5) <Color html='#800000' rgb=(0.5, 0, 0)> >>> Color('green') + Color('grey').red <Color html='#808000' rgb=(0.501961, 0.501961, 0)>
You can even manipulate non-primary attributes like hue, saturation, and lightness with standard addition, subtraction or multiplication operators:
>>> Color.from_hls(0.5, 0.5, 1.0) <Color html='#00ffff' rgb=(0, 1, 1)> >>> Color.from_hls(0.5, 0.5, 1.0) * Lightness(0.8) <Color html='#00cccc' rgb=(0, 0.8, 0.8)> >>> (Color.from_hls(0.5, 0.5, 1.0) * Lightness(0.8)).hls HLS(h=0.5, l=0.4, s=1.0)
In the last example above, a
Color
instance is constructed from HLS (hue, lightness, saturation) values with a lightness of 0.5. This is multiplied by aLightness
a value of 0.8 which constructs a newColor
with the same hue and saturation, but a lightness of 0.4 (0.8 × 0.5).If an instance is converted to a string (with
str()
) it will return a string containing the 7-character HTML code for the color (e.g. “#ff0000” for red). As can be seen in the examples above, a similar representation is included for the output ofrepr()
. The output ofrepr()
can be customized by assigning values toColor.repr_style
.-
repr_style
¶ Specifies the style of output returned when using
repr()
against aColor
instance. This is an attribute of the class, not of instances. For example:>>> Color('#f00') <Color html='#ff0000' rgb=(1, 0, 0)> >>> Color.repr_style = 'html' >>> Color('#f00') Color('#ff0000')
The following values are valid:
- ‘default’ - The style shown above
- ‘term16m’ - Similar to the default style, but instead of the HTML style being included, a swatch previewing the color is output. Note that the terminal must support 24-bit color ANSI codes for this to work.
- ‘term256’ - Similar to ‘termtrue’, but uses the closest color that can be found in the standard 256-color xterm palette. Note that the terminal must support 8-bit color ANSI codes for this to work.
- ‘html’ - Outputs a valid
Color
constructor using the HTML style, e.g.Color('#ff99bb')
- ‘rgb’ - Outputs a valid
Color
constructor using the floating point RGB values, e.g.Color(1, 0.25, 0)
-
difference
(other, method='euclid')[source]¶ Determines the difference between this color and other using the specified method.
Parameters: - other (Color) – The color to compare this color to.
- method (str) –
The algorithm to use in the comparison. Valid values are:
- ’euclid’ - This is the default method. Calculate the Euclidian distance. This is by far the fastest method, but also the least accurate in terms of human perception.
- ’cie1976’ - Use the CIE 1976 formula for calculating the difference between two colors in CIE Lab space.
- ’cie1994g’ - Use the CIE 1994 formula with the “graphic arts” bias for calculating the difference.
- ’cie1994t’ - Use the CIE 1994 forumula with the “textiles” bias for calculating the difference.
- ’ciede2000’ - Use the CIEDE 2000 formula for calculating the difference.
Returns: A
float
indicating how different the two colors are. Note that the Euclidian distance will be significantly different to the other calculations; effectively this just measures the distance between the two colors by treating them as coordinates in a three dimensional Euclidian space. All other methods are means of calculating a Delta E value in which 2.3 is considered a just-noticeable difference (JND).For example:
>>> Color('red').difference(Color('red')) 0.0 >>> Color('red').difference(Color('red'), method='cie1976') 0.0 >>> Color('red').difference(Color('#900')) 0.4 >>> Color('red').difference(Color('#900'), method='cie1976') 40.17063087142142 >>> Color('red').difference(Color('#900'), method='ciede2000') 21.078146289272155 >>> Color('red').difference(Color('blue')) 1.4142135623730951 >>> Color('red').difference(Color('blue'), method='cie1976') 176.31403908880046
-
classmethod
from_cmy
(c, m, y)[source]¶ Construct a
Color
from CMY (cyan, magenta, yellow) floats between 0.0 and 1.0.Note
This conversion uses the basic subtractive method which is not accurate for color reproduction on print devices. See the Color FAQ for more information.
-
classmethod
from_cmyk
(c, m, y, k)[source]¶ Construct a
Color
from CMYK (cyan, magenta, yellow, black) floats between 0.0 and 1.0.Note
This conversion uses the basic subtractive method which is not accurate for color reproduction on print devices. See the Color FAQ for more information.
-
classmethod
from_hls
(h, l, s)[source]¶ Construct a
Color
from HLS (hue, lightness, saturation) floats between 0.0 and 1.0.
-
classmethod
from_hsv
(h, s, v)[source]¶ Construct a
Color
from HSV (hue, saturation, value) floats between 0.0 and 1.0.
-
classmethod
from_lab
(l, a, b)[source]¶ Construct a
Color
from (L*, a*, b*) float values representing a color in the CIE Lab color space. The conversion assumes the sRGB working space with reference white D65.
-
classmethod
from_luv
(l, u, v)[source]¶ Construct a
Color
from (L*, u*, v*) float values representing a color in the CIE Luv color space. The conversion assumes the sRGB working space with reference white D65.
-
classmethod
from_rgb
(r, g, b)[source]¶ Construct a
Color
from three linear RGB float values between 0.0 and 1.0.
-
classmethod
from_rgb24
(n)[source]¶ Construct a
Color
from an unsigned 24-bit integer number of the form 0x00BBGGRR.
-
classmethod
from_rgb565
(n)[source]¶ Construct a
Color
from an unsigned 16-bit integer number in RGB565 format.
-
classmethod
from_rgb_bytes
(r, g, b)[source]¶ Construct a
Color
from three RGB byte values between 0 and 255.
-
classmethod
from_string
(s)[source]¶ Construct a
Color
from a 4 or 7 character CSS-like representation (e.g. “#f00” or “#ff0000” for red), or from one of the named colors (e.g. “green” or “wheat”) from the CSS standard. Any other string format will result in aValueError
.
-
classmethod
from_xyz
(x, y, z)[source]¶ Construct a
Color
from (X, Y, Z) float values representing a color in the CIE 1931 color space. The conversion assumes the sRGB working space with reference white D65.
-
classmethod
from_yiq
(y, i, q)[source]¶ Construct a
Color
from three Y’IQ float values. Y’ can be between 0.0 and 1.0, while I and Q can be between -1.0 and 1.0.
-
classmethod
from_yuv
(y, u, v)[source]¶ Construct a
Color
from three Y’UV float values. The Y value may be between 0.0 and 1.0. U may be between -0.436 and 0.436, while V may be between -0.615 and 0.615.
-
classmethod
from_yuv_bytes
(y, u, v)[source]¶ Construct a
Color
from three Y’UV byte values between 0 and 255. The U and V values are biased by 128 to prevent negative values as is typical in video applications. The Y value is biased by 16 for the same purpose.
-
gradient
(other, steps=10, easing=<function linear>)[source]¶ Returns a generator which fades between this color and other in the specified number of steps.
Parameters: - other (Color) – The color that will end the gradient (with the color the method is called upon starting the gradient)
- steps (int) – The unqiue number of colors to include in the generated gradient. Defaults to 10 if unspecified.
- easing (callable) – A function which controls the speed of the progression. If
specified, if must be a function which takes a single parameter,
the number of steps, and yields a sequence of values between 0.0
(representing the start of the gradient) and 1.0 (representing the
end). The default is
linear()
.
Returns: A generator yielding steps
Color
instances which fade from this color to other.For example:
>>> Color.repr_style = 'html' >>> print('\n'.join( ... repr(c) for c in ... Color('red').gradient(Color('green')) ... )) Color('#ff0000') Color('#e30e00') Color('#c61c00') Color('#aa2b00') Color('#8e3900') Color('#714700') Color('#555500') Color('#396400') Color('#1c7200') Color('#008000')
New in version 1.1.
-
cmy
¶ Returns a 3-tuple of (cyan, magenta, yellow) float values (between 0.0 and 1.0).
Note
This conversion uses the basic subtractive method which is not accurate for color reproduction on print devices. See the Color FAQ for more information.
-
cmyk
¶ Returns a 4-tuple of (cyan, magenta, yellow, black) float values (between 0.0 and 1.0).
Note
This conversion uses the basic subtractive method which is not accurate for color reproduction on print devices. See the Color FAQ for more information.
-
hls
¶ Returns a 3-tuple of (hue, lightness, saturation) float values (between 0.0 and 1.0).
-
hsv
¶ Returns a 3-tuple of (hue, saturation, value) float values (between 0.0 and 1.0).
-
html
¶ Returns the color as a string in HTML #RRGGBB format.
-
hue
¶ Returns the hue of the color as a
Hue
instance which can be used in operations with otherColor
instances.
-
lab
¶ Returns a 3-tuple of (L*, a*, b*) float values representing the color in the CIE Lab color space with the D65 standard illuminant.
-
lightness
¶ Returns the lightness of the color as a
Lightness
instance which can be used in operations with otherColor
instances.
-
luma
¶ Returns the luma of the color as a
Luma
instance which can be used in operations with otherColor
instances.
-
luv
¶ Returns a 3-tuple of (L*, u*, v*) float values representing the color in the CIE Luv color space with the D65 standard illuminant.
-
rgb
¶ Return a simple 3-tuple of (r, g, b) float values in the range 0.0 <= n <= 1.0.
Note
The
Color
class can already be treated as such a 3-tuple but for the cases where you want a straightnamedtuple()
this property is available.
-
rgb565
¶ Returns an unsigned 16-bit integer number representing the color in the RGB565 encoding.
-
rgb_bytes
¶ Returns a 3-tuple of (red, green, blue) byte values.
-
saturation
¶ Returns the saturation of the color as a
Saturation
instance which can be used in operations with otherColor
instances.
-
xyz
¶ Returns a 3-tuple of (X, Y, Z) float values representing the color in the CIE 1931 color space. The conversion assumes the sRGB working space, with reference white D65.
-
yiq
¶ Returns a 3-tuple of (y, i, q) float values; y values can be between 0.0 and 1.0, whilst i and q values can be between -1.0 and 1.0.
-
yuv
¶ Returns a 3-tuple of (y, u, v) float values; Y values can be between 0.0 and 1.0, U values are between -0.436 and 0.436, and V values are between -0.615 and 0.615.
-
yuv_bytes
¶ Returns a 3-tuple of (y, u, v) byte values. Y values are biased by 16 in the result to prevent negatives. U and V values are biased by 128 for the same purpose.
-
Format Strings¶
Instances of Color
can be used in format strings to output ANSI escape
sequences to color text. Format specifications can be used to modify the output
to support different terminal types. For example:
>>> red = Color('red')
>>> green = Color('green')
>>> blue = Color('#47b')
>>> print(repr("{red}Red{red:0} Alert!".format(red=red)))
'\\x1b[1;31mRed\\x1b[0m Alert!'
>>> print(repr("The grass is {green:16m}greener{green:0}.".format(
... green=green)))
'The grass is \\x1b[38;2;0;128;0mgreener\\x1b[0m.'
>>> print(repr("{blue:b16m}Blue skies{blue:0}".format(blue=blue)))
'\\x1b[48;2;68;119;187mBlue skies\\x1b[0m'
The format specification is an optional foreground / background specifier (the letters “f” or “b”) followed by an optional terminal type identifer, which is one of:
- “8” - the default, indicating only the original 8 DOS colors are supported (technically, 16 foreground colors are supported via use of the “bold” style for “intense” colors)
- “256” - indicates the terminal supports 256 colors via 8-bit color ANSI codes
- “16m” - indicating the terminal supports ≈16 million colors via 24-bit color ANSI codes
Alternately, “0” can be specified indicating that the style should be reset. If specified with the optional foreground / background specifier, “0” resets only the foreground / background color. If specified alone it resets all styles. More formally:
<fore_back> ::= "" | "f" | "b"
<type> ::= "" | "0" | "8" | "256" | "16m"
<format_spec> ::= <fore_back> <type>
New in version 1.1: The ability to output ANSI codes via format strings, and the
customization of repr()
output.
Manipulation Classes¶
These manipulation classes are used in conjunction with the standard arithmetic
addition, subtraction, and multiplication operators to calculate new
Color
instances.
-
class
colorzero.
Red
[source]¶ Represents the red component of a
Color
for use in transformations. Instances of this class can be constructed directly with a float value, or by querying theColor.red
attribute. Addition, subtraction, and multiplication are supported withColor
instances. For example:>>> Color.from_rgb(0, 0, 0) + Red(0.5) <Color html='#800000' rgb=(0.5, 0, 0)> >>> Color('#f00') - Color('#900').red <Color html='#660000' rgb=(0.4, 0, 0)> >>> (Red(0.1) * Color('red')).red Red(0.1)
-
class
colorzero.
Green
[source]¶ Represents the green component of a
Color
for use in transformations. Instances of this class can be constructed directly with a float value, or by querying theColor.green
attribute. Addition, subtraction, and multiplication are supported withColor
instances. For example:>>> Color(0, 0, 0) + Green(0.1) <Color html='#001a00' rgb=(0, 0.1, 0)> >>> Color.from_yuv(1, -0.4, -0.6) - Green(1) <Color html='#510030' rgb=(0.316098, 0, 0.187156)> >>> (Green(0.5) * Color('white')).rgb RGB(r=1.0, g=0.5, b=1.0)
-
class
colorzero.
Blue
[source]¶ Represents the blue component of a
Color
for use in transformations. Instances of this class can be constructed directly with a float value, or by querying theColor.blue
attribute. Addition, subtraction, and multiplication are supported withColor
instances. For example:>>> Color(0, 0, 0) + Blue(0.2) <Color html='#000033' rgb=(0, 0, 0.2)> >>> Color.from_hls(0.5, 0.5, 1.0) - Blue(1) <Color html='#00ff00' rgb=(0, 1, 0)> >>> Blue(0.9) * Color('white') <Color html='#ffffe6' rgb=(1, 1, 0.9)>
-
class
colorzero.
Hue
[source]¶ Represents the hue of a
Color
for use in transformations. Instances of this class can be constructed directly with a float value in the range [0.0, 1.0) representing an angle around the HSL hue wheel. As this is a circular mapping, 0.0 and 1.0 effectively mean the same thing, i.e. out of range values will be normalized into the range [0.0, 1.0).The class can also be constructed with the keyword arguments
deg
orrad
if you wish to specify the hue value in degrees or radians instead, respectively. Instances can also be constructed by querying theColor.hue
attribute.Addition, subtraction, and multiplication are supported with
Color
instances. For example:>>> Color(1, 0, 0).hls HLS(h=0.0, l=0.5, s=1.0) >>> (Color(1, 0, 0) + Hue(deg=180)).hls HLS(h=0.5, l=0.5, s=1.0)
Note that whilst multiplication by a
Hue
doesn’t make much sense, it is still supported. However, the circular nature of a hue value can lead to suprising effects. In particular, since 1.0 is equivalent to 0.0 the following may be observed:>>> (Hue(1.0) * Color.from_hls(0.5, 0.5, 1.0)).hls HLS(h=0.0, l=0.5, s=1.0)
-
deg
¶ Returns the hue as a value in degrees with the range 0.0 <= n < 360.0.
-
rad
¶ Returns the hue as a value in radians with the range 0.0 <= n < 2π.
-
-
class
colorzero.
Saturation
[source]¶ Represents the saturation of a
Color
for use in transformations. Instances of this class can be constructed directly with a float value, or by querying theColor.saturation
attribute. Addition, subtraction, and multiplication are supported withColor
instances. For example:>>> Color(0.9, 0.9, 0.6) + Saturation(0.1) <Color html='#ecec93' rgb=(0.925, 0.925, 0.575)> >>> Color('red') - Saturation(1) <Color html='#808080' rgb=(0.5, 0.5, 0.5)> >>> Saturation(0.5) * Color('wheat') <Color html='#e4d9c3' rgb=(0.896078, 0.85098, 0.766667)>
-
class
colorzero.
Lightness
[source]¶ Represents the lightness of a
Color
for use in transformations. Instances of this class can be constructed directly with a float value, or by querying theColor.lightness
attribute. Addition, subtraction, and multiplication are supported withColor
instances. For example:>>> Color(0, 0, 0) + Lightness(0.1) <Color html='#1a1a1a' rgb=(0.1, 0.1, 0.1)> >>> Color.from_rgb_bytes(0x80, 0x80, 0) - Lightness(0.2) <Color html='#1a1a00' rgb=(0.101961, 0.101961, 0)> >>> Lightness(0.9) * Color('wheat') <Color html='#f0ce8e' rgb=(0.94145, 0.806785, 0.555021)>
-
class
colorzero.
Luma
[source]¶ Represents the luma of a
Color
for use in transformations. Instances of this class can be constructed directly with a float value, or by querying theColor.yuv.y
attribute. Addition, subtraction, and multiplication are supported withColor
instances. For example:>>> Color(0, 0, 0) + Luma(0.1) <Color html='#1a1a1a' rgb=(0.1, 0.1, 0.1)> >>> Color('red') * Luma(0.5) <Color html='#d90000' rgb=(0.8505, 0, 0)>
Difference Functions¶
-
colorzero.
euclid
(color1, color2)[source]¶ Calculates color difference as a simple Euclidean distance by treating the three components as spatial dimensions.
Note
This function will return considerably different values to the other difference functions. In particular, the maximum “difference” will be √3 which is much smaller than the output of the CIE functions.
-
colorzero.
cie1976
(color1, color2)[source]¶ Calculates color difference according to the CIE 1976 formula. Effectively this is the Euclidean formula, but with CIE L*a*b* components instead of RGB.
-
colorzero.
cie1994g
(color1, color2)[source]¶ Calculates color difference according to the CIE 1994 formula with the “textile” bias. See
cie1994()
for further information.
-
colorzero.
cie1994t
(color1, color2)[source]¶ Calculates color difference according to the CIE 1994 formula with the “graphics” bias. See
cie1994()
for further information.
-
colorzero.
ciede2000
(color1, color2)[source]¶ Calculates color difference according to the CIEDE 2000 formula. This is the most accurate algorithm currently implemented but also the most complex and slowest. Like CIE1994 it is largely based in CIE L*C*h* space, but with several modifications to account for perceptual uniformity flaws.
Easing Functions¶
These functions can be used with the Color.gradient()
method to control
the progression of the fade between the two colors.
-
colorzero.
ease_in
(steps)[source]¶ Quadratic ease-in function; yields steps values between 0.0 and 1.0
Development¶
The main GitHub repository for the project can be found at:
Anyone is more than welcome to open tickets to discuss bugs, new features, or just to ask usage questions (I find this useful for gauging what questions ought to feature in the FAQ, for example).
Even if you don’t feel up to hacking on the code, I’d love to hear suggestions from people of what you’d like the API to look like (even if the code itself isn’t particularly pythonic, the interface should be)!
Development installation¶
If you wish to develop colorzero itself, it is easiest to obtain the source by cloning the GitHub repository and then use the “develop” target of the Makefile which will install the package as a link to the cloned repository allowing in-place development (it also builds a tags file for use with vim/emacs with Exuberant’s ctags utility). The following example demonstrates this method within a virtual Python environment:
$ sudo apt install lsb-release build-essential git git-core \
exuberant-ctags virtualenvwrapper python-virtualenv python3-virtualenv
$ cd
$ mkvirtualenv -p /usr/bin/python3 colorzero
$ workon colorzero
(colorzero) $ git clone https://github.com/waveform80/colorzero.git
(colorzero) $ cd colorzero
(colorzero) $ make develop
To pull the latest changes from git into your clone and update your installation:
$ workon colorzero
(colorzero) $ cd ~/colorzero
(colorzero) $ git pull
(colorzero) $ make develop
To remove your installation, destroy the sandbox and the clone:
(colorzero) $ deactivate
$ rmvirtualenv colorzero
$ rm -fr ~/colorzero
Building the docs¶
If you wish to build the docs, you’ll need a few more dependencies. Inkscape is used for conversion of SVGs to other formats, Graphviz is used for rendering certain charts, and TeX Live is required for building PDF output. The following command should install all required dependencies:
$ sudo apt install texlive-latex-recommended texlive-latex-extra \
texlive-fonts-recommended graphviz inkscape
Once these are installed, you can use the “doc” target to build the documentation:
$ workon colorzero
(colorzero) $ cd ~/colorzero
(colorzero) $ make doc
The HTML output is written to build/html
while the PDF output goes to
build/latex
.
Test suite¶
If you wish to run the colorzero test suite, follow the instructions in Development installation above and then make the “test” target within the sandbox:
$ workon colorzero
(colorzero) $ cd ~/colorzero
(colorzero) $ make test
Change log¶
Release 1.1 (2018-05-15)¶
- Added ability to generate ANSI codes with Format Strings.
- Added
Color.gradient()
method. - Exposed the various difference functions in the API (
euclid()
,cie1976()
, etc). - Various doc fixes and enhancements.
License¶
Copyright 2016-2018 Dave Jones
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
- 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.
- Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
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 HOLDER 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.