Codebase list grapefruit / a874152
New upstream release Jonathan Carter 2 years ago
24 changed file(s) with 856 addition(s) and 1157 deletion(s). Raw diff Collapse all Expand all
0 2016-08-01
1 - Realease 0.1a4
2 - Fixed missing attribute grapefruit_test.py
3
04 2008-06-15
15 - Released 0.1a3
26 - Added Gradient
(No changes)
(No changes)
+0
-149
PKG-INFO less more
0 Metadata-Version: 1.0
1 Name: grapefruit
2 Version: 0.1a3
3 Summary: A module to manipulate color information easily.
4 Home-page: http://code.google.com/p/grapefruit/
5 Author: Xavier Basty
6 Author-email: xbasty@gmail.com
7 License: Apache License 2.0
8 Download-URL: http://grapefruit.googlecode.com/files/grapefruit-0.1a3.tar.gz
9 Description: =====================
10 README for GrapeFruit
11 =====================
12
13 Installing
14 ============
15
16 **From the sources:**
17
18 Download the latest grapefruit library from:
19
20 http://code.google.com/p/grapefruit/
21
22
23 Untar the source distribution and run::
24
25 $ python setup.py build
26 $ python setup.py install
27
28
29 Testing
30 =========
31
32 With setuptools installed::
33
34 $ python setup.py test
35
36 Without setuptools installed::
37
38 $ python grapefruit_test.py
39
40
41 Getting the code
42 ==================
43
44 View the trunk at:
45
46 http://grapefruit.googlecode.com/svn/trunk/
47
48 Check out the latest development version anonymously with::
49
50 $ svn checkout http://grapefruit.googlecode.com/svn/trunk/ GrapeFruit
51
52 Documentation
53 ===============
54
55 You can download a compiled version of the documentation at:
56
57 http://http://code.google.com/p/grapefruit/downloads/list?q=label:Type-Docs
58
59 The documentation is generated from reStructuredText sources by Sphinx.
60 If you need to build it, go into the doc folder and run::
61
62 make <builder>
63
64 Or, if you're running windows::
65
66 makedoc.cmd
67
68
69 License
70 =========
71
72 ::
73
74 Copyright (c) 2008, Xavier Basty
75
76 Licensed under the Apache License, Version 2.0 (the "License");
77 you may not use this file except in compliance with the License.
78 You may obtain a copy of the License at
79
80 http://www.apache.org/licenses/LICENSE-2.0
81
82 Unless required by applicable law or agreed to in writing, software
83 distributed under the License is distributed on an "AS IS" BASIS,
84 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
85 See the License for the specific language governing permissions and
86 limitations under the License.
87
88 2008-06-15
89 - Released 0.1a3
90 - Added Gradient
91
92 2008-06-01
93 - Fixed overflow in alpha blending.
94
95 2008-05-29
96 - Added Saturate/Desaturate.
97 - Added MonochromeScheme
98 - Added the mode parameter to the generation methods to choose the
99 color wheel use for the generation (ryb/rgb).
100
101 2008-05-28
102 - Added the RGB<->RYB hue conversion.
103 - Added an angle parameter to the tetrad scheme to control the shape of
104 the rectangle.
105
106 2008-05-27
107 - Released 0.1a2
108
109 2008-05-24
110
111 - Fixed the HSL->RGB conversion
112 (the modulo in the hue conversion was 60 instead of 6.0!)
113 Updated the unit tests (which were wrong!)
114
115 2008-05-24
116
117 Released 0.1a1
118 - Convert the documentation to Sphinx
119 - Completed the unit tests
120 - Fixed some stupid typos
121
122 2008-05-22
123
124 - Refactored pretty much everything to more standard "Python coding style".
125 - Replaced the global variables by Color properties.
126 - Moved the module functions to static methods of Color.
127 - Completed the CIE white point dictionary to include all the standard
128 illuminants.
129 - Added doctest for all the functions.
130 - Fixed the conversions factors to get better results (more exact and
131 more symmetric).
132 - Changed the range of the L component from [0~1] to [0~100] (as it should
133 have been).
134 - Added packaging data and setup.
135 - Changed the structure of the unit tests.
136
137 2008-05-08
138
139 Released 0.1a0
140 - Initial checkin of grapefruit
141
142 Keywords: color conversion
143 Platform: UNKNOWN
144 Classifier: Development Status :: 3 - Alpha
145 Classifier: Intended Audience :: Developers
146 Classifier: License :: OSI Approved :: Apache Software License
147 Classifier: Topic :: Software Development :: Libraries :: Python Modules
148 Classifier: Topic :: Multimedia :: Graphics
+0
-78
README less more
0 =====================
1 README for GrapeFruit
2 =====================
3
4 Installing
5 ============
6
7 **From the sources:**
8
9 Download the latest grapefruit library from:
10
11 http://code.google.com/p/grapefruit/
12
13
14 Untar the source distribution and run::
15
16 $ python setup.py build
17 $ python setup.py install
18
19
20 Testing
21 =========
22
23 With setuptools installed::
24
25 $ python setup.py test
26
27 Without setuptools installed::
28
29 $ python grapefruit_test.py
30
31
32 Getting the code
33 ==================
34
35 View the trunk at:
36
37 http://grapefruit.googlecode.com/svn/trunk/
38
39 Check out the latest development version anonymously with::
40
41 $ svn checkout http://grapefruit.googlecode.com/svn/trunk/ GrapeFruit
42
43 Documentation
44 ===============
45
46 You can download a compiled version of the documentation at:
47
48 http://http://code.google.com/p/grapefruit/downloads/list?q=label:Type-Docs
49
50 The documentation is generated from reStructuredText sources by Sphinx.
51 If you need to build it, go into the doc folder and run::
52
53 make <builder>
54
55 Or, if you're running windows::
56
57 makedoc.cmd
58
59
60 License
61 =========
62
63 ::
64
65 Copyright (c) 2008, Xavier Basty
66
67 Licensed under the Apache License, Version 2.0 (the "License");
68 you may not use this file except in compliance with the License.
69 You may obtain a copy of the License at
70
71 http://www.apache.org/licenses/LICENSE-2.0
72
73 Unless required by applicable law or agreed to in writing, software
74 distributed under the License is distributed on an "AS IS" BASIS,
75 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
76 See the License for the specific language governing permissions and
77 limitations under the License.
0 =====================
1 README for GrapeFruit
2 =====================
3
4 GrapeFruit is a pure Python module that let you easily manipulate and convert color information.
5 Its Primary goal is to be *natural* and *flexible*.
6
7 The following color systems are supported by GrapeFruit:
8 * RGB (sRGB)
9 * HSL
10 * HSV
11 * YIQ
12 * YUV
13 * CIE-XYZ
14 * CIE-LAB (with the illuminant you want)
15 * CMY
16 * CMYK
17 * HTML/CSS color definition (#RRGGBB, #RGB or the X11 color name)
18 * RYB (artistic color wheel
19 Installing
20 ============
21
22 **From the sources:**
23
24 Download the latest grapefruit library from:
25
26 https://github.com/xav/Grapefruit
27
28
29 Untar the source distribution and run::
30
31 $ python setup.py build
32 $ python setup.py install
33
34
35 Testing
36 =========
37
38 With setuptools installed::
39
40 $ python setup.py test
41
42 Without setuptools installed::
43
44 $ python grapefruit_test.py
45
46
47 Documentation
48 ===============
49
50 You can download a compiled version of the documentation at:
51
52 https://github.com/xav/Grapefruit/downloads
53
54 The documentation is generated from reStructuredText sources by Sphinx.
55 If you need to build it, go into the doc folder and run::
56
57 make <builder>
58
59 Or, if you're running windows::
60
61 makedoc.cmd
62
63
64 License
65 =========
66
67 ::
68
69 Copyright (c) 2008, Xavier Basty
70
71 Licensed under the Apache License, Version 2.0 (the "License");
72 you may not use this file except in compliance with the License.
73 You may obtain a copy of the License at
74
75 http://www.apache.org/licenses/LICENSE-2.0
76
77 Unless required by applicable law or agreed to in writing, software
78 distributed under the License is distributed on an "AS IS" BASIS,
79 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
80 See the License for the specific language governing permissions and
81 limitations under the License.
(No changes)
0 grapefruit (0.1~a4+dfsg-1) unstable; urgency=medium
1
2 * New upstream release
3 * Update debian/watch file
4 * Remove patches that are no longer required
5
6 -- Jonathan Carter <jcc@debian.org> Fri, 21 Jan 2022 12:19:03 +0200
7
08 grapefruit (0.1~a3+dfsg-10) unstable; urgency=medium
19
210 [ Ondřej Nový ]
0 Document: grapefruit
1 Title: Grapefruit
2 Author: Xavier Basty
3 Abstract: Python module to manipulate color information easily
4 Section: Graphics
5
6 Format: HTML
7 Index: /usr/share/doc/python3-grapefruit/html/index.html
8 Files: /usr/share/doc/python3-grapefruit/html/*.html
0 doc/_build/html
0 grapefruit_0.1~a4+dfsg-1_source.buildinfo python optional
+0
-83
debian/patches/0002-Fix-syntax-for-python3-support-keeping-python2-compa.patch less more
0 From 2d8a62a62e9871cb4a75d8487cb7818b0efba66d Mon Sep 17 00:00:00 2001
1 From: Vincent Danjean <vdanjean@debian.org>
2 Date: Wed, 27 Jun 2018 23:12:26 +0200
3 Subject: Fix syntax for python3 support (keeping python2 compatibility)
4
5 ---
6 grapefruit.py | 10 +++++++---
7 grapefruit_test.py | 9 ++++++---
8 2 files changed, 13 insertions(+), 6 deletions(-)
9
10 diff --git a/grapefruit.py b/grapefruit.py
11 index 43d68f1..f6e5738 100755
12 --- a/grapefruit.py
13 +++ b/grapefruit.py
14 @@ -17,6 +17,10 @@
15
16 '''GrapeFruit - Color manipulation in Python'''
17
18 +# both next line to support python3
19 +from functools import reduce
20 +from past.builtins import xrange
21 +
22 # $Id: grapefruit.py 30 2008-06-01 20:44:26Z xbasty $
23 __author__ = 'Xavier Basty <xbasty@gmail.com>'
24 __version__ = '0.1a3'
25 @@ -285,7 +289,7 @@ class Color:
26
27 '''
28 if not(isinstance(values, tuple)):
29 - raise TypeError, 'values must be a tuple'
30 + raise TypeError('values must be a tuple')
31
32 if mode=='rgb':
33 self.__rgb = values
34 @@ -921,7 +925,7 @@ class Color:
35 html = html.strip().lower()
36 if html[0]=='#':
37 html = html[1:]
38 - elif Color.NAMED_COLOR.has_key(html):
39 + elif html in Color.NAMED_COLOR:
40 html = Color.NAMED_COLOR[html][1:]
41
42 if len(html)==6:
43 @@ -929,7 +933,7 @@ class Color:
44 elif len(html)==3:
45 rgb = ['%c%c' % (v,v) for v in html]
46 else:
47 - raise ValueError, 'input #%s is not in #RRGGBB format' % html
48 + raise ValueError('input #%s is not in #RRGGBB format' % html)
49
50 return tuple(((int(n, 16) / 255.0) for n in rgb))
51
52 diff --git a/grapefruit_test.py b/grapefruit_test.py
53 index 5693c24..0aa0541 100755
54 --- a/grapefruit_test.py
55 +++ b/grapefruit_test.py
56 @@ -21,6 +21,9 @@
57 __author__ = 'xbasty@gmail.com'
58 __version__ = '0.1a3'
59
60 +# next line to support python3
61 +from past.builtins import xrange
62 +
63 import unittest
64 import grapefruit
65
66 @@ -32,13 +35,13 @@ class GrapeFruitTestCase(unittest.TestCase):
67 '''
68 if hasattr(first,'__iter__') and hasattr(second,'__iter__'):
69 if len(first) != len(second):
70 - raise self.failureException, (msg or "%r != %r" % (first, second))
71 + raise self.failureException(msg or "%r != %r" % (first, second))
72
73 for f, s in zip(first, second):
74 if abs(s-f) > diff:
75 - raise self.failureException, (msg or "%r != %r @ %f" % (first, second, diff))
76 + raise self.failureException(msg or "%r != %r @ %f" % (first, second, diff))
77 elif abs(second-first) > diff:
78 - raise self.failureException, (msg or "%r != %r @ %f" % (first, second, diff))
79 + raise self.failureException(msg or "%r != %r @ %f" % (first, second, diff))
80 assertNear = failUnlessNear
81
82 class ConversionTest(GrapeFruitTestCase):
+0
-184
debian/patches/fix-typos less more
0 From aee26db9a7961ef6645c04d17876dd10789a5a79 Mon Sep 17 00:00:00 2001
1 From: Simon Chopin <chopin.simon@gmail.com>
2 Date: Thu, 8 Oct 2015 09:14:38 -0700
3 Subject: Fix typos in comments and doc.
4
5 Bug: http://code.google.com/p/grapefruit/issues/detail?id=7
6 Last-Update: 2013-04-30
7 Patch-Name: fix-typos
8 ---
9 doc/index.rst | 6 +++---
10 grapefruit.py | 26 +++++++++++++-------------
11 grapefruit_test.py | 4 ++--
12 3 files changed, 18 insertions(+), 18 deletions(-)
13
14 diff --git a/doc/index.rst b/doc/index.rst
15 index f000ef4..53a845f 100755
16 --- a/doc/index.rst
17 +++ b/doc/index.rst
18 @@ -18,7 +18,7 @@ The Color class
19 .. class:: Color
20
21 The grapefruit module contains only the :class:`Color` class, which exposes all
22 -the functionnalities. It can be used to store a color value and manipulate it,
23 +the functionalities. It can be used to store a color value and manipulate it,
24 or convert it to another color system.
25
26 If you are only interested in converting you colors from one system to another,
27 @@ -42,7 +42,7 @@ of the :class:`Color` class, and all the properties are read-only.
28
29 Some operations may provide results a bit outside the specified ranges,
30 the results are not capped.
31 - This is due to certain color systems having a widers gamut than others.
32 + This is due to certain color systems having a wider gamut than others.
33
34
35 Class content
36 @@ -423,7 +423,7 @@ Generation methods
37 The generation methods let you create a color scheme by using a color as the
38 start point.
39
40 -All the method, appart from Gradient and MonochromeScheme, have a 'mode'
41 +All the method, apart from Gradient and MonochromeScheme, have a 'mode'
42 parameter that let you choose which color wheel should be used to generate
43 the scheme.
44
45 diff --git a/grapefruit.py b/grapefruit.py
46 index 4b88742..43d68f1 100755
47 --- a/grapefruit.py
48 +++ b/grapefruit.py
49 @@ -1111,7 +1111,7 @@ class Color:
50
51 @staticmethod
52 def NewFromRgb(r, g, b, alpha=1.0, wref=_DEFAULT_WREF):
53 - '''Create a new instance based on the specifed RGB values.
54 + '''Create a new instance based on the specified RGB values.
55
56 Parameters:
57 :r:
58 @@ -1138,7 +1138,7 @@ class Color:
59
60 @staticmethod
61 def NewFromHsl(h, s, l, alpha=1.0, wref=_DEFAULT_WREF):
62 - '''Create a new instance based on the specifed HSL values.
63 + '''Create a new instance based on the specified HSL values.
64
65 Parameters:
66 :h:
67 @@ -1165,7 +1165,7 @@ class Color:
68
69 @staticmethod
70 def NewFromHsv(h, s, v, alpha=1.0, wref=_DEFAULT_WREF):
71 - '''Create a new instance based on the specifed HSV values.
72 + '''Create a new instance based on the specified HSV values.
73
74 Parameters:
75 :h:
76 @@ -1193,7 +1193,7 @@ class Color:
77
78 @staticmethod
79 def NewFromYiq(y, i, q, alpha=1.0, wref=_DEFAULT_WREF):
80 - '''Create a new instance based on the specifed YIQ values.
81 + '''Create a new instance based on the specified YIQ values.
82
83 Parameters:
84 :y:
85 @@ -1220,7 +1220,7 @@ class Color:
86
87 @staticmethod
88 def NewFromYuv(y, u, v, alpha=1.0, wref=_DEFAULT_WREF):
89 - '''Create a new instance based on the specifed YUV values.
90 + '''Create a new instance based on the specified YUV values.
91
92 Parameters:
93 :y:
94 @@ -1247,7 +1247,7 @@ class Color:
95
96 @staticmethod
97 def NewFromXyz(x, y, z, alpha=1.0, wref=_DEFAULT_WREF):
98 - '''Create a new instance based on the specifed CIE-XYZ values.
99 + '''Create a new instance based on the specified CIE-XYZ values.
100
101 Parameters:
102 :x:
103 @@ -1274,7 +1274,7 @@ class Color:
104
105 @staticmethod
106 def NewFromLab(l, a, b, alpha=1.0, wref=_DEFAULT_WREF):
107 - '''Create a new instance based on the specifed CIE-LAB values.
108 + '''Create a new instance based on the specified CIE-LAB values.
109
110 Parameters:
111 :l:
112 @@ -1305,7 +1305,7 @@ class Color:
113
114 @staticmethod
115 def NewFromCmy(c, m, y, alpha=1.0, wref=_DEFAULT_WREF):
116 - '''Create a new instance based on the specifed CMY values.
117 + '''Create a new instance based on the specified CMY values.
118
119 Parameters:
120 :c:
121 @@ -1332,7 +1332,7 @@ class Color:
122
123 @staticmethod
124 def NewFromCmyk(c, m, y, k, alpha=1.0, wref=_DEFAULT_WREF):
125 - '''Create a new instance based on the specifed CMYK values.
126 + '''Create a new instance based on the specified CMYK values.
127
128 Parameters:
129 :c:
130 @@ -1361,7 +1361,7 @@ class Color:
131
132 @staticmethod
133 def NewFromHtml(html, alpha=1.0, wref=_DEFAULT_WREF):
134 - '''Create a new instance based on the specifed HTML color definition.
135 + '''Create a new instance based on the specified HTML color definition.
136
137 Parameters:
138 :html:
139 @@ -1392,7 +1392,7 @@ class Color:
140
141 @staticmethod
142 def NewFromPil(pil, alpha=1.0, wref=_DEFAULT_WREF):
143 - '''Create a new instance based on the specifed PIL color.
144 + '''Create a new instance based on the specified PIL color.
145
146 Parameters:
147 :pil:
148 @@ -1834,11 +1834,11 @@ class Color:
149 Color((h2, s, l), 'hsl', self.__a, self.__wref))
150
151 def TetradicScheme(self, angle=30, mode='ryb'):
152 - '''Return three colors froming a tetrad with this one.
153 + '''Return three colors forming a tetrad with this one.
154
155 Parameters:
156 :angle:
157 - The angle to substract from the adjacent colors hues [-90...90].
158 + The angle to subtract from the adjacent colors hues [-90...90].
159 You can use an angle of zero to generate a square tetrad.
160 :mode:
161 Select which color wheel to use for the generation (ryb/rgb).
162 diff --git a/grapefruit_test.py b/grapefruit_test.py
163 index cf3aba0..5693c24 100755
164 --- a/grapefruit_test.py
165 +++ b/grapefruit_test.py
166 @@ -28,7 +28,7 @@ class GrapeFruitTestCase(unittest.TestCase):
167 def failUnlessNear(self, first, second, diff=9e-5, msg=None):
168 '''
169 Fail if the difference between the two objects is greater
170 - than a certain amout (default 9e-5).
171 + than a certain amount (default 9e-5).
172 '''
173 if hasattr(first,'__iter__') and hasattr(second,'__iter__'):
174 if len(first) != len(second):
175 @@ -112,7 +112,7 @@ class ConversionTest(GrapeFruitTestCase):
176 self.assertEqual((0.6, 0.6, 0.6), grapefruit.Color.RgbToGreyscale(1, 0.8, 0))
177
178 class NewFromTest(GrapeFruitTestCase):
179 - '''Test the static color instanciation methods.'''
180 + '''Test the static color instantiation methods.'''
181 def testNewFromRgb(self):
182 c = grapefruit.Color.NewFromRgb(1.0, 0.5, 0.0)
183 self.assertEqual(c, (1.0, 0.5, 0.0, 1.0))
0 fix-typos
1 0002-Fix-syntax-for-python3-support-keeping-python2-compa.patch
20 remove-grapefruit-image
0 version=3
0 version=4
11 opts=uversionmangle=s/(a|b|rc)/~$1/,dversionmangle=s/\+dfsg//; \
2 https://github.com/xav/Grapefruit/downloads \
3 /downloads/xav/Grapefruit/grapefruit-(.+?)(?:\.tar)?\.tar\.gz
2 https://github.com/xav/Grapefruit/tags .*/v?(\d\S+)\.tar\.gz
3 #/downloads/xav/Grapefruit/grapefruit-(.+?)(?:\.tar)?\.tar\.gz
(No changes)
Binary diff not shown
1010 # All configuration values have a default value; values that are commented out
1111 # serve to show the default value.
1212 #
13 # $Id: conf.py 14 2008-05-24 09:46:30Z xbasty $
13 # $Id$
1414
1515 import sys, os
1616
(No changes)
(No changes)
11 # -*- coding: utf-8 -*-#
22
33 # Copyright (c) 2008, Xavier Basty
4 #
4 #
55 # Licensed under the Apache License, Version 2.0 (the "License");
66 # you may not use this file except in compliance with the License.
77 # You may obtain a copy of the License at
8 #
8 #
99 # http://www.apache.org/licenses/LICENSE-2.0
10 #
10 #
1111 # Unless required by applicable law or agreed to in writing, software
1212 # distributed under the License is distributed on an "AS IS" BASIS,
1313 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1616
1717 '''GrapeFruit - Color manipulation in Python'''
1818
19 # $Id: grapefruit.py 30 2008-06-01 20:44:26Z xbasty $
19 from __future__ import division
20
21 import sys
22
23 # $Id$
2024 __author__ = 'Xavier Basty <xbasty@gmail.com>'
2125 __version__ = '0.1a3'
2226
5256
5357 class Color:
5458 '''Hold a color value.
55
59
5660 Example usage:
57
61
5862 To create an instance of the grapefruit.Color from RGB values:
59
63
6064 >>> import grapefruit
6165 >>> r, g, b = 1, 0.5, 0
6266 >>> col = grapefruit.Color.NewFromRgb(r, g, b)
63
67
6468 To get the values of the color in another colorspace:
65
69
6670 >>> h, s, v = col.hsv
6771 >>> l, a, b = col.lab
68
72
6973 To get the complementary of a color:
70
71 >>> compl = col.ComplementaryColor()
72 >>> print compl.hsl
74
75 >>> compl = col.ComplementaryColor(mode='rgb')
76 >>> print(compl.hsl)
7377 (210.0, 1.0, 0.5)
74
78
7579 To directly convert RGB values to their HSL equivalent:
76
80
7781 >>> h, s, l = Color.RgbToHsl(r, g, b)
78
82
7983 '''
8084
8185 WHITE_REFERENCE = {
119123 'sup_F10' : (0.99001, 1.00000, 0.83134),
120124 'sup_F11' : (1.03820, 1.00000, 0.65555),
121125 'sup_F12' : (1.11428, 1.00000, 0.40353)}
122
126
123127 NAMED_COLOR = {
124128 'aliceblue': '#f0f8ff',
125129 'antiquewhite': '#faebd7',
271275
272276 def __init__(self, values, mode='rgb', alpha=1.0, wref=_DEFAULT_WREF):
273277 '''Instantiate a new grapefruit.Color object.
274
278
275279 Parameters:
276280 :values:
277281 The values of this color, in the specified representation.
284288
285289 '''
286290 if not(isinstance(values, tuple)):
287 raise TypeError, 'values must be a tuple'
291 raise TypeError('values must be a tuple')
288292
289293 if mode=='rgb':
290294 self.__rgb = values
305309 try:
306310 if isinstance(other, Color):
307311 return (self.__rgb==other.__rgb) and (self.__a==other.__a)
308
309312 if len(other) != 4:
310313 return False
311 rgba = self.__rgb + (self.__a,)
312 return reduce(lambda x, y: x and (y[0]==y[1]), zip(rgba, other), True)
314 return list(self.__rgb + (self.__a,)) == list(other)
313315 except TypeError:
314316 return False
315317 except AttributeError:
320322
321323 def __str__(self):
322324 '''A string representation of this grapefruit.Color instance.
323
325
324326 Returns:
325327 The RGBA representation of this grapefruit.Color instance.
326
328
327329 '''
328330 return '(%g, %g, %g, %g)' % (self.__rgb + (self.__a,))
329331
330 def __unicode__(self):
331 '''A unicode string representation of this grapefruit.Color instance.
332
333 Returns:
334 The RGBA representation of this grapefruit.Color instance.
335
336 '''
337 return u'(%g, %g, %g, %g)' % (self.__rgb + (self.__a,))
332 if sys.version_info[0] < 3:
333 def __unicode__(self):
334 '''A unicode string representation of this grapefruit.Color instance.
335
336 Returns:
337 The RGBA representation of this grapefruit.Color instance.
338
339 '''
340 return unicode('%g, %g, %g, %g)') % (self.__rgb + (self.__a,))
338341
339342 def __iter__(self):
340343 return iter(self.__rgb + (self.__a,))
342345 def __len__(self):
343346 return 4
344347
348 def __GetIsLegal(self):
349 return all(0.0 <= v <= 1.0 for v in self)
350 isLegal = property(fget=__GetIsLegal, doc='Boolean indicating whether the color is within the legal gamut.')
351
352 def __GetNearestLegal(self):
353 def clamp(x, lo, hi):
354 if x < lo:
355 return lo
356 elif x > hi:
357 return hi
358 else:
359 return x
360 return Color.NewFromRgb(*[clamp(v, 0.0, 1.0) for v in self])
361 nearestLegal = property(fget=__GetNearestLegal, doc='The nearest legal color.')
362
345363 @staticmethod
346364 def RgbToHsl(r, g, b):
347365 '''Convert the color from RGB coordinates to HSL.
348
366
349367 Parameters:
350368 :r:
351369 The Red component value [0...1]
353371 The Green component value [0...1]
354372 :b:
355373 The Blue component value [0...1]
356
374
357375 Returns:
358376 The color as an (h, s, l) tuple in the range:
359377 h[0...360],
362380
363381 >>> Color.RgbToHsl(1, 0.5, 0)
364382 (30.0, 1.0, 0.5)
365
383
366384 '''
367385 minVal = min(r, g, b) # min RGB value
368386 maxVal = max(r, g, b) # max RGB value
384402 h = 2.0 + dr - db
385403 else:
386404 h = 4.0 + dg - dr
387
405
388406 h = (h*60.0) % 360.0
389407 return (h, s, l)
390408
399417 @staticmethod
400418 def HslToRgb(h, s, l):
401419 '''Convert the color from HSL coordinates to RGB.
402
420
403421 Parameters:
404422 :h:
405423 The Hue component value [0...1]
407425 The Saturation component value [0...1]
408426 :l:
409427 The Lightness component value [0...1]
410
428
411429 Returns:
412430 The color as an (r, g, b) tuple in the range:
413431 r[0...1],
414432 g[0...1],
415433 b[0...1]
416
434
417435 >>> Color.HslToRgb(30.0, 1.0, 0.5)
418436 (1.0, 0.5, 0.0)
419
437
420438 '''
421439 if s==0: return (l, l, l) # achromatic (gray)
422440
436454 @staticmethod
437455 def RgbToHsv(r, g, b):
438456 '''Convert the color from RGB coordinates to HSV.
439
457
440458 Parameters:
441459 :r:
442460 The Red component value [0...1]
444462 The Green component value [0...1]
445463 :b:
446464 The Blue component value [0...1]
447
465
448466 Returns:
449467 The color as an (h, s, v) tuple in the range:
450468 h[0...360],
451469 s[0...1],
452470 v[0...1]
453
471
454472 >>> Color.RgbToHsv(1, 0.5, 0)
455 (30.0, 1, 1)
456
457 '''
458 v = max(r, g, b)
459 d = v - min(r, g, b)
473 (30.0, 1.0, 1.0)
474
475 '''
476 v = float(max(r, g, b))
477 d = v - min(r, g, b)
460478 if d==0: return (0.0, 0.0, v)
461479 s = d / v
462480
468486 h = 2.0 + dr - db # between cyan & yellow
469487 else: # b==v
470488 h = 4.0 + dg - dr # between magenta & cyan
471
489
472490 h = (h*60.0) % 360.0
473491 return (h, s, v)
474492
475493 @staticmethod
476494 def HsvToRgb(h, s, v):
477495 '''Convert the color from RGB coordinates to HSV.
478
496
479497 Parameters:
480498 :h:
481499 The Hus component value [0...1]
483501 The Saturation component value [0...1]
484502 :v:
485503 The Value component [0...1]
486
504
487505 Returns:
488506 The color as an (r, g, b) tuple in the range:
489507 r[0...1],
490508 g[0...1],
491509 b[0...1]
492
510
493511 >>> Color.HslToRgb(30.0, 1.0, 0.5)
494512 (1.0, 0.5, 0.0)
495
513
496514 '''
497515 if s==0: return (v, v, v) # achromatic (gray)
498
516
499517 h /= 60.0
500518 h = h % 6.0
501519
502520 i = int(h)
503521 f = h - i
504522 if not(i&1): f = 1-f # if i is even
505
523
506524 m = v * (1.0 - s)
507525 n = v * (1.0 - (s * f))
508
526
509527 if i==0: return (v, n, m)
510528 if i==1: return (n, v, m)
511529 if i==2: return (m, v, n)
516534 @staticmethod
517535 def RgbToYiq(r, g, b):
518536 '''Convert the color from RGB to YIQ.
519
537
520538 Parameters:
521539 :r:
522540 The Red component value [0...1]
524542 The Green component value [0...1]
525543 :b:
526544 The Blue component value [0...1]
527
545
528546 Returns:
529547 The color as an (y, i, q) tuple in the range:
530548 y[0...1],
531549 i[0...1],
532550 q[0...1]
533
551
534552 >>> '(%g, %g, %g)' % Color.RgbToYiq(1, 0.5, 0)
535553 '(0.592263, 0.458874, -0.0499818)'
536
554
537555 '''
538556 y = (r * 0.29895808) + (g * 0.58660979) + (b *0.11443213)
539557 i = (r * 0.59590296) - (g * 0.27405705) - (b *0.32184591)
543561 @staticmethod
544562 def YiqToRgb(y, i, q):
545563 '''Convert the color from YIQ coordinates to RGB.
546
564
547565 Parameters:
548566 :y:
549567 Tte Y component value [0...1]
551569 The I component value [0...1]
552570 :q:
553571 The Q component value [0...1]
554
572
555573 Returns:
556574 The color as an (r, g, b) tuple in the range:
557575 r[0...1],
558576 g[0...1],
559577 b[0...1]
560
578
561579 >>> '(%g, %g, %g)' % Color.YiqToRgb(0.592263, 0.458874, -0.0499818)
562 '(1, 0.5, 5.442e-007)'
563
580 '(1, 0.5, 5.442e-07)'
581
564582 '''
565583 r = y + (i * 0.9562) + (q * 0.6210)
566584 g = y - (i * 0.2717) - (q * 0.6485)
570588 @staticmethod
571589 def RgbToYuv(r, g, b):
572590 '''Convert the color from RGB coordinates to YUV.
573
591
574592 Parameters:
575593 :r:
576594 The Red component value [0...1]
578596 The Green component value [0...1]
579597 :b:
580598 The Blue component value [0...1]
581
599
582600 Returns:
583601 The color as an (y, u, v) tuple in the range:
584602 y[0...1],
585603 u[-0.436...0.436],
586604 v[-0.615...0.615]
587
605
588606 >>> '(%g, %g, %g)' % Color.RgbToYuv(1, 0.5, 0)
589607 '(0.5925, -0.29156, 0.357505)'
590
608
591609 '''
592610 y = (r * 0.29900) + (g * 0.58700) + (b * 0.11400)
593611 u = -(r * 0.14713) - (g * 0.28886) + (b * 0.43600)
597615 @staticmethod
598616 def YuvToRgb(y, u, v):
599617 '''Convert the color from YUV coordinates to RGB.
600
618
601619 Parameters:
602620 :y:
603621 The Y component value [0...1]
605623 The U component value [-0.436...0.436]
606624 :v:
607625 The V component value [-0.615...0.615]
608
626
609627 Returns:
610628 The color as an (r, g, b) tuple in the range:
611629 r[0...1],
612630 g[0...1],
613631 b[0...1]
614
632
615633 >>> '(%g, %g, %g)' % Color.YuvToRgb(0.5925, -0.2916, 0.3575)
616 '(0.999989, 0.500015, -6.3276e-005)'
617
634 '(0.999989, 0.500015, -6.3276e-05)'
635
618636 '''
619637 r = y + (v * 1.13983)
620638 g = y - (u * 0.39465) - (v * 0.58060)
624642 @staticmethod
625643 def RgbToXyz(r, g, b):
626644 '''Convert the color from sRGB to CIE XYZ.
627
645
628646 The methods assumes that the RGB coordinates are given in the sRGB
629647 colorspace (D65).
630
648
631649 .. note::
632
650
633651 Compensation for the sRGB gamma correction is applied before converting.
634
652
635653 Parameters:
636654 :r:
637655 The Red component value [0...1]
639657 The Green component value [0...1]
640658 :b:
641659 The Blue component value [0...1]
642
660
643661 Returns:
644662 The color as an (x, y, z) tuple in the range:
645663 x[0...1],
646664 y[0...1],
647665 z[0...1]
648
666
649667 >>> '(%g, %g, %g)' % Color.RgbToXyz(1, 0.5, 0)
650668 '(0.488941, 0.365682, 0.0448137)'
651
669
652670 '''
653671 r, g, b = [((v <= 0.03928) and [v / 12.92] or [((v+0.055) / 1.055) **2.4])[0] for v in (r, g, b)]
654
672
655673 x = (r * 0.4124) + (g * 0.3576) + (b * 0.1805)
656674 y = (r * 0.2126) + (g * 0.7152) + (b * 0.0722)
657675 z = (r * 0.0193) + (g * 0.1192) + (b * 0.9505)
662680 '''Convert the color from CIE XYZ coordinates to sRGB.
663681
664682 .. note::
665
683
666684 Compensation for sRGB gamma correction is applied before converting.
667
685
668686 Parameters:
669687 :x:
670688 The X component value [0...1]
672690 The Y component value [0...1]
673691 :z:
674692 The Z component value [0...1]
675
693
676694 Returns:
677695 The color as an (r, g, b) tuple in the range:
678696 r[0...1],
679697 g[0...1],
680698 b[0...1]
681
699
682700 >>> '(%g, %g, %g)' % Color.XyzToRgb(0.488941, 0.365682, 0.0448137)
683 '(1, 0.5, 6.81883e-008)'
684
701 '(1, 0.5, 6.81883e-08)'
702
685703 '''
686704 r = (x * 3.2406255) - (y * 1.5372080) - (z * 0.4986286)
687705 g = -(x * 0.9689307) + (y * 1.8757561) + (z * 0.0415175)
691709 @staticmethod
692710 def XyzToLab(x, y, z, wref=_DEFAULT_WREF):
693711 '''Convert the color from CIE XYZ to CIE L*a*b*.
694
712
695713 Parameters:
696714 :x:
697715 The X component value [0...1]
701719 The Z component value [0...1]
702720 :wref:
703721 The whitepoint reference, default is 2° D65.
704
722
705723 Returns:
706724 The color as an (L, a, b) tuple in the range:
707725 L[0...100],
708726 a[-1...1],
709727 b[-1...1]
710
728
711729 >>> '(%g, %g, %g)' % Color.XyzToLab(0.488941, 0.365682, 0.0448137)
712730 '(66.9518, 0.43084, 0.739692)'
713
731
714732 >>> '(%g, %g, %g)' % Color.XyzToLab(0.488941, 0.365682, 0.0448137, Color.WHITE_REFERENCE['std_D50'])
715733 '(66.9518, 0.411663, 0.67282)'
716
734
717735 '''
718736 # White point correction
719737 x /= wref[0]
720738 y /= wref[1]
721739 z /= wref[2]
722
740
723741 # Nonlinear distortion and linear transformation
724742 x, y, z = [((v > 0.008856) and [v**_oneThird] or [(7.787 * v) + _sixteenHundredsixteenth])[0] for v in (x, y, z)]
725
743
726744 # Vector scaling
727745 l = (116 * y) - 16
728746 a = 5.0 * (x - y)
729747 b = 2.0 * (y - z)
730
748
731749 return (l, a, b)
732750
733751 @staticmethod
734752 def LabToXyz(l, a, b, wref=_DEFAULT_WREF):
735753 '''Convert the color from CIE L*a*b* to CIE 1931 XYZ.
736
754
737755 Parameters:
738756 :l:
739757 The L component [0...100]
743761 The a component [-1...1]
744762 :wref:
745763 The whitepoint reference, default is 2° D65.
746
764
747765 Returns:
748766 The color as an (x, y, z) tuple in the range:
749767 x[0...q],
750768 y[0...1],
751769 z[0...1]
752
770
753771 >>> '(%g, %g, %g)' % Color.LabToXyz(66.9518, 0.43084, 0.739692)
754772 '(0.488941, 0.365682, 0.0448137)'
755
773
756774 >>> '(%g, %g, %g)' % Color.LabToXyz(66.9518, 0.411663, 0.67282, Color.WHITE_REFERENCE['std_D50'])
757775 '(0.488941, 0.365682, 0.0448138)'
758
776
759777 '''
760778 y = (l + 16) / 116
761779 x = (a / 5.0) + y
765783 @staticmethod
766784 def CmykToCmy(c, m, y, k):
767785 '''Convert the color from CMYK coordinates to CMY.
768
786
769787 Parameters:
770788 :c:
771789 The Cyan component value [0...1]
775793 The Yellow component value [0...1]
776794 :k:
777795 The Black component value [0...1]
778
796
779797 Returns:
780798 The color as an (c, m, y) tuple in the range:
781799 c[0...1],
782800 m[0...1],
783801 y[0...1]
784
802
785803 >>> '(%g, %g, %g)' % Color.CmykToCmy(1, 0.32, 0, 0.5)
786804 '(1, 0.66, 0.5)'
787
805
788806 '''
789807 mk = 1-k
790808 return ((c*mk + k), (m*mk + k), (y*mk + k))
792810 @staticmethod
793811 def CmyToCmyk(c, m, y):
794812 '''Convert the color from CMY coordinates to CMYK.
795
813
796814 Parameters:
797815 :c:
798816 The Cyan component value [0...1]
800818 The Magenta component value [0...1]
801819 :y:
802820 The Yellow component value [0...1]
803
821
804822 Returns:
805823 The color as an (c, m, y, k) tuple in the range:
806824 c[0...1],
807825 m[0...1],
808826 y[0...1],
809827 k[0...1]
810
828
811829 >>> '(%g, %g, %g, %g)' % Color.CmyToCmyk(1, 0.66, 0.5)
812830 '(1, 0.32, 0, 0.5)'
813
831
814832 '''
815833 k = min(c, m, y)
816834 if k==1.0: return (0.0, 0.0, 0.0, 1.0)
820838 @staticmethod
821839 def RgbToCmy(r, g, b):
822840 '''Convert the color from RGB coordinates to CMY.
823
841
824842 Parameters:
825843 :r:
826844 The Red component value [0...1]
828846 The Green component value [0...1]
829847 :b:
830848 The Blue component value [0...1]
831
849
832850 Returns:
833851 The color as an (c, m, y) tuple in the range:
834852 c[0...1],
835853 m[0...1],
836854 y[0...1]
837
855
838856 >>> Color.RgbToCmy(1, 0.5, 0)
839857 (0, 0.5, 1)
840
858
841859 '''
842860 return (1-r, 1-g, 1-b)
843861
844862 @staticmethod
845863 def CmyToRgb(c, m, y):
846864 '''Convert the color from CMY coordinates to RGB.
847
865
848866 Parameters:
849867 :c:
850868 The Cyan component value [0...1]
852870 The Magenta component value [0...1]
853871 :y:
854872 The Yellow component value [0...1]
855
873
856874 Returns:
857875 The color as an (r, g, b) tuple in the range:
858876 r[0...1],
859877 g[0...1],
860878 b[0...1]
861
879
862880 >>> Color.CmyToRgb(0, 0.5, 1)
863881 (1, 0.5, 0)
864
882
865883 '''
866884 return (1-c, 1-m, 1-y)
867885
868886 @staticmethod
869 def RgbToHtml(r, g, b):
870 '''Convert the color from (r, g, b) to #RRGGBB.
871
887 def RgbToIntTuple(r, g, b):
888 '''Convert the color from (r, g, b) to an int tuple.
889
872890 Parameters:
873891 :r:
874892 The Red component value [0...1]
876894 The Green component value [0...1]
877895 :b:
878896 The Blue component value [0...1]
879
880 Returns:
881 A CSS string representation of this color (#RRGGBB).
882
883 >>> Color.RgbToHtml(1, 0.5, 0)
884 '#ff8000'
885
886 '''
887 return '#%02x%02x%02x' % tuple((min(round(v*255), 255) for v in (r, g, b)))
888
889 @staticmethod
890 def HtmlToRgb(html):
891 '''Convert the HTML color to (r, g, b).
892
893 Parameters:
894 :html:
895 the HTML definition of the color (#RRGGBB or #RGB or a color name).
896
897
898 Returns:
899 The color as an (r, g, b) tuple in the range:
900 r[0...255],
901 g[0...2551],
902 b[0...2551]
903
904 >>> Color.RgbToIntTuple(1, 0.5, 0)
905 (255, 128, 0)
906
907 '''
908 return tuple(int(round(v*255)) for v in (r, g, b))
909
910 @staticmethod
911 def IntTupleToRgb(intTuple):
912 '''Convert a tuple of ints to (r, g, b).
913
914 Parameters:
915 The color as an (r, g, b) integer tuple in the range:
916 r[0...255],
917 g[0...255],
918 b[0...255]
919
897920 Returns:
898921 The color as an (r, g, b) tuple in the range:
899922 r[0...1],
900923 g[0...1],
901924 b[0...1]
902
925
926 >>> '(%g, %g, %g)' % Color.IntTupleToRgb((255, 128, 0))
927 '(1, 0.501961, 0)'
928
929 '''
930 return tuple(v / 255 for v in intTuple)
931
932 @staticmethod
933 def RgbToHtml(r, g, b):
934 '''Convert the color from (r, g, b) to #RRGGBB.
935
936 Parameters:
937 :r:
938 The Red component value [0...1]
939 :g:
940 The Green component value [0...1]
941 :b:
942 The Blue component value [0...1]
943
944 Returns:
945 A CSS string representation of this color (#RRGGBB).
946
947 >>> Color.RgbToHtml(1, 0.5, 0)
948 '#ff8000'
949
950 '''
951 return '#%02x%02x%02x' % tuple((min(round(v*255), 255) for v in (r, g, b)))
952
953 @staticmethod
954 def HtmlToRgb(html):
955 '''Convert the HTML color to (r, g, b).
956
957 Parameters:
958 :html:
959 the HTML definition of the color (#RRGGBB or #RGB or a color name).
960
961 Returns:
962 The color as an (r, g, b) tuple in the range:
963 r[0...1],
964 g[0...1],
965 b[0...1]
966
903967 Throws:
904968 :ValueError:
905969 If html is neither a known color name or a hexadecimal RGB
906970 representation.
907
971
908972 >>> '(%g, %g, %g)' % Color.HtmlToRgb('#ff8000')
909973 '(1, 0.501961, 0)'
910974 >>> '(%g, %g, %g)' % Color.HtmlToRgb('ff8000')
915979 '(1, 0.4, 0)'
916980 >>> '(%g, %g, %g)' % Color.HtmlToRgb('lemonchiffon')
917981 '(1, 0.980392, 0.803922)'
918
982
919983 '''
920984 html = html.strip().lower()
921985 if html[0]=='#':
922986 html = html[1:]
923 elif Color.NAMED_COLOR.has_key(html):
987 elif html in Color.NAMED_COLOR:
924988 html = Color.NAMED_COLOR[html][1:]
925989
926990 if len(html)==6:
928992 elif len(html)==3:
929993 rgb = ['%c%c' % (v,v) for v in html]
930994 else:
931 raise ValueError, 'input #%s is not in #RRGGBB format' % html
932
995 raise ValueError('input #%s is not in #RRGGBB format' % html)
996
933997 return tuple(((int(n, 16) / 255.0) for n in rgb))
934998
935999 @staticmethod
9361000 def RgbToPil(r, g, b):
9371001 '''Convert the color from RGB to a PIL-compatible integer.
938
1002
9391003 Parameters:
9401004 :r:
9411005 The Red component value [0...1]
9431007 The Green component value [0...1]
9441008 :b:
9451009 The Blue component value [0...1]
946
1010
9471011 Returns:
9481012 A PIL compatible integer (0xBBGGRR).
949
1013
9501014 >>> '0x%06x' % Color.RgbToPil(1, 0.5, 0)
9511015 '0x0080ff'
952
1016
9531017 '''
9541018 r, g, b = [min(int(round(v*255)), 255) for v in (r, g, b)]
9551019 return (b << 16) + (g << 8) + r
9571021 @staticmethod
9581022 def PilToRgb(pil):
9591023 '''Convert the color from a PIL-compatible integer to RGB.
960
1024
9611025 Parameters:
9621026 pil: a PIL compatible color representation (0xBBGGRR)
9631027 Returns:
9661030 r: [0...1]
9671031 g: [0...1]
9681032 b: [0...1]
969
1033
9701034 >>> '(%g, %g, %g)' % Color.PilToRgb(0x0080ff)
9711035 '(1, 0.501961, 0)'
972
1036
9731037 '''
9741038 r = 0xff & pil
9751039 g = 0xff & (pil >> 8)
9791043 @staticmethod
9801044 def _WebSafeComponent(c, alt=False):
9811045 '''Convert a color component to its web safe equivalent.
982
1046
9831047 Parameters:
9841048 :c:
9851049 The component value [0...1]
9861050 :alt:
9871051 If True, return the alternative value instead of the nearest one.
988
1052
9891053 Returns:
9901054 The web safe equivalent of the component value.
991
1055
9921056 '''
9931057 # This sucks, but floating point between 0 and 1 is quite fuzzy...
9941058 # So we just change the scale a while to make the equality tests
9951059 # work, otherwise it gets wrong at some decimal far to the right.
9961060 sc = c * 100.0
997
1061
9981062 # If the color is already safe, return it straight away
9991063 d = sc % 20
10001064 if d==0: return c
1001
1065
10021066 # Get the lower and upper safe values
10031067 l = sc - d
10041068 u = l + 20
1005
1069
10061070 # Return the 'closest' value according to the alt flag
10071071 if alt:
10081072 if (sc-l) >= (u-sc): return l/100.0
10141078 @staticmethod
10151079 def RgbToWebSafe(r, g, b, alt=False):
10161080 '''Convert the color from RGB to 'web safe' RGB
1017
1081
10181082 Parameters:
10191083 :r:
10201084 The Red component value [0...1]
10251089 :alt:
10261090 If True, use the alternative color instead of the nearest one.
10271091 Can be used for dithering.
1028
1092
10291093 Returns:
10301094 The color as an (r, g, b) tuple in the range:
10311095 the range:
10321096 r[0...1],
10331097 g[0...1],
10341098 b[0...1]
1035
1099
10361100 >>> '(%g, %g, %g)' % Color.RgbToWebSafe(1, 0.55, 0.0)
10371101 '(1, 0.6, 0)'
1038
1102
10391103 '''
10401104 webSafeComponent = Color._WebSafeComponent
10411105 return tuple((webSafeComponent(v, alt) for v in (r, g, b)))
10511115 The Green component value [0...1]
10521116 :b:
10531117 The Blue component value [0...1]
1054
1118
10551119 Returns:
10561120 The color as an (r, g, b) tuple in the range:
10571121 the range:
10581122 r[0...1],
10591123 g[0...1],
10601124 b[0...1]
1061
1125
10621126 >>> '(%g, %g, %g)' % Color.RgbToGreyscale(1, 0.8, 0)
10631127 '(0.6, 0.6, 0.6)'
1064
1128
10651129 '''
10661130 v = (r + g + b) / 3.0
10671131 return (v, v, v)
10691133 @staticmethod
10701134 def RgbToRyb(hue):
10711135 '''Maps a hue on the RGB color wheel to Itten's RYB wheel.
1072
1136
10731137 Parameters:
10741138 :hue:
10751139 The hue on the RGB color wheel [0...360]
1076
1140
10771141 Returns:
10781142 An approximation of the corresponding hue on Itten's RYB wheel.
1079
1143
10801144 >>> Color.RgbToRyb(15)
1081 26
1082
1145 26.0
1146
10831147 '''
10841148 d = hue % 15
10851149 i = int(hue / 15)
10861150 x0 = _RybWheel[i]
10871151 x1 = _RybWheel[i+1]
10881152 return x0 + (x1-x0) * d / 15
1089
1153
10901154 @staticmethod
10911155 def RybToRgb(hue):
10921156 '''Maps a hue on Itten's RYB color wheel to the standard RGB wheel.
1093
1157
10941158 Parameters:
10951159 :hue:
10961160 The hue on Itten's RYB color wheel [0...360]
1097
1161
10981162 Returns:
10991163 An approximation of the corresponding hue on the standard RGB wheel.
1100
1164
11011165 >>> Color.RybToRgb(15)
1102 8
1103
1166 8.0
1167
11041168 '''
11051169 d = hue % 15
11061170 i = int(hue / 15)
11111175 @staticmethod
11121176 def NewFromRgb(r, g, b, alpha=1.0, wref=_DEFAULT_WREF):
11131177 '''Create a new instance based on the specifed RGB values.
1114
1178
11151179 Parameters:
11161180 :r:
11171181 The Red component value [0...1]
11231187 The color transparency [0...1], default is opaque
11241188 :wref:
11251189 The whitepoint reference, default is 2° D65.
1126
1190
11271191 Returns:
11281192 A grapefruit.Color instance.
1129
1193
11301194 >>> Color.NewFromRgb(1.0, 0.5, 0.0)
11311195 (1.0, 0.5, 0.0, 1.0)
11321196 >>> Color.NewFromRgb(1.0, 0.5, 0.0, 0.5)
11331197 (1.0, 0.5, 0.0, 0.5)
1134
1198
11351199 '''
11361200 return Color((r, g, b), 'rgb', alpha, wref)
11371201
11381202 @staticmethod
11391203 def NewFromHsl(h, s, l, alpha=1.0, wref=_DEFAULT_WREF):
11401204 '''Create a new instance based on the specifed HSL values.
1141
1205
11421206 Parameters:
11431207 :h:
11441208 The Hue component value [0...1]
11501214 The color transparency [0...1], default is opaque
11511215 :wref:
11521216 The whitepoint reference, default is 2° D65.
1153
1217
11541218 Returns:
11551219 A grapefruit.Color instance.
1156
1220
11571221 >>> Color.NewFromHsl(30, 1, 0.5)
11581222 (1.0, 0.5, 0.0, 1.0)
11591223 >>> Color.NewFromHsl(30, 1, 0.5, 0.5)
11601224 (1.0, 0.5, 0.0, 0.5)
1161
1225
11621226 '''
11631227 return Color((h, s, l), 'hsl', alpha, wref)
11641228
11651229 @staticmethod
11661230 def NewFromHsv(h, s, v, alpha=1.0, wref=_DEFAULT_WREF):
11671231 '''Create a new instance based on the specifed HSV values.
1168
1232
11691233 Parameters:
11701234 :h:
11711235 The Hus component value [0...1]
11771241 The color transparency [0...1], default is opaque
11781242 :wref:
11791243 The whitepoint reference, default is 2° D65.
1180
1244
11811245 Returns:
11821246 A grapefruit.Color instance.
1183
1247
11841248 >>> Color.NewFromHsv(30, 1, 1)
11851249 (1.0, 0.5, 0.0, 1.0)
11861250 >>> Color.NewFromHsv(30, 1, 1, 0.5)
11871251 (1.0, 0.5, 0.0, 0.5)
1188
1252
11891253 '''
11901254 h2, s, l = Color.RgbToHsl(*Color.HsvToRgb(h, s, v))
11911255 return Color((h, s, l), 'hsl', alpha, wref)
11931257 @staticmethod
11941258 def NewFromYiq(y, i, q, alpha=1.0, wref=_DEFAULT_WREF):
11951259 '''Create a new instance based on the specifed YIQ values.
1196
1260
11971261 Parameters:
11981262 :y:
11991263 The Y component value [0...1]
12051269 The color transparency [0...1], default is opaque
12061270 :wref:
12071271 The whitepoint reference, default is 2° D65.
1208
1272
12091273 Returns:
12101274 A grapefruit.Color instance.
1211
1275
12121276 >>> str(Color.NewFromYiq(0.5922, 0.45885,-0.05))
1213 '(0.999902, 0.499955, -6.6905e-005, 1)'
1277 '(0.999902, 0.499955, -6.6905e-05, 1)'
12141278 >>> str(Color.NewFromYiq(0.5922, 0.45885,-0.05, 0.5))
1215 '(0.999902, 0.499955, -6.6905e-005, 0.5)'
1279 '(0.999902, 0.499955, -6.6905e-05, 0.5)'
12161280
12171281 '''
12181282 return Color(Color.YiqToRgb(y, i, q), 'rgb', alpha, wref)
12201284 @staticmethod
12211285 def NewFromYuv(y, u, v, alpha=1.0, wref=_DEFAULT_WREF):
12221286 '''Create a new instance based on the specifed YUV values.
1223
1287
12241288 Parameters:
12251289 :y:
12261290 The Y component value [0...1]
12321296 The color transparency [0...1], default is opaque
12331297 :wref:
12341298 The whitepoint reference, default is 2° D65.
1235
1299
12361300 Returns:
12371301 A grapefruit.Color instance.
1238
1302
12391303 >>> str(Color.NewFromYuv(0.5925, -0.2916, 0.3575))
1240 '(0.999989, 0.500015, -6.3276e-005, 1)'
1304 '(0.999989, 0.500015, -6.3276e-05, 1)'
12411305 >>> str(Color.NewFromYuv(0.5925, -0.2916, 0.3575, 0.5))
1242 '(0.999989, 0.500015, -6.3276e-005, 0.5)'
1306 '(0.999989, 0.500015, -6.3276e-05, 0.5)'
12431307
12441308 '''
12451309 return Color(Color.YuvToRgb(y, u, v), 'rgb', alpha, wref)
12471311 @staticmethod
12481312 def NewFromXyz(x, y, z, alpha=1.0, wref=_DEFAULT_WREF):
12491313 '''Create a new instance based on the specifed CIE-XYZ values.
1250
1314
12511315 Parameters:
12521316 :x:
12531317 The Red component value [0...1]
12591323 The color transparency [0...1], default is opaque
12601324 :wref:
12611325 The whitepoint reference, default is 2° D65.
1262
1326
12631327 Returns:
12641328 A grapefruit.Color instance.
1265
1329
12661330 >>> str(Color.NewFromXyz(0.488941, 0.365682, 0.0448137))
1267 '(1, 0.5, 6.81883e-008, 1)'
1331 '(1, 0.5, 6.81883e-08, 1)'
12681332 >>> str(Color.NewFromXyz(0.488941, 0.365682, 0.0448137, 0.5))
1269 '(1, 0.5, 6.81883e-008, 0.5)'
1333 '(1, 0.5, 6.81883e-08, 0.5)'
12701334
12711335 '''
12721336 return Color(Color.XyzToRgb(x, y, z), 'rgb', alpha, wref)
12741338 @staticmethod
12751339 def NewFromLab(l, a, b, alpha=1.0, wref=_DEFAULT_WREF):
12761340 '''Create a new instance based on the specifed CIE-LAB values.
1277
1341
12781342 Parameters:
12791343 :l:
12801344 The L component [0...100]
12861350 The color transparency [0...1], default is opaque
12871351 :wref:
12881352 The whitepoint reference, default is 2° D65.
1289
1353
12901354 Returns:
12911355 A grapefruit.Color instance.
1292
1356
12931357 >>> str(Color.NewFromLab(66.9518, 0.43084, 0.739692))
1294 '(1, 0.5, 1.09491e-008, 1)'
1358 '(1, 0.5, 1.09491e-08, 1)'
12951359 >>> str(Color.NewFromLab(66.9518, 0.43084, 0.739692, wref=Color.WHITE_REFERENCE['std_D50']))
12961360 '(1.01238, 0.492011, -0.14311, 1)'
12971361 >>> str(Color.NewFromLab(66.9518, 0.43084, 0.739692, 0.5))
1298 '(1, 0.5, 1.09491e-008, 0.5)'
1362 '(1, 0.5, 1.09491e-08, 0.5)'
12991363 >>> str(Color.NewFromLab(66.9518, 0.43084, 0.739692, 0.5, Color.WHITE_REFERENCE['std_D50']))
13001364 '(1.01238, 0.492011, -0.14311, 0.5)'
1301
1365
13021366 '''
13031367 return Color(Color.XyzToRgb(*Color.LabToXyz(l, a, b, wref)), 'rgb', alpha, wref)
13041368
13051369 @staticmethod
13061370 def NewFromCmy(c, m, y, alpha=1.0, wref=_DEFAULT_WREF):
13071371 '''Create a new instance based on the specifed CMY values.
1308
1372
13091373 Parameters:
13101374 :c:
13111375 The Cyan component value [0...1]
13171381 The color transparency [0...1], default is opaque
13181382 :wref:
13191383 The whitepoint reference, default is 2° D65.
1320
1384
13211385 Returns:
13221386 A grapefruit.Color instance.
1323
1387
13241388 >>> Color.NewFromCmy(0, 0.5, 1)
13251389 (1, 0.5, 0, 1.0)
13261390 >>> Color.NewFromCmy(0, 0.5, 1, 0.5)
13271391 (1, 0.5, 0, 0.5)
1328
1392
13291393 '''
13301394 return Color(Color.CmyToRgb(c, m, y), 'rgb', alpha, wref)
13311395
13321396 @staticmethod
13331397 def NewFromCmyk(c, m, y, k, alpha=1.0, wref=_DEFAULT_WREF):
13341398 '''Create a new instance based on the specifed CMYK values.
1335
1399
13361400 Parameters:
13371401 :c:
13381402 The Cyan component value [0...1]
13461410 The color transparency [0...1], default is opaque
13471411 :wref:
13481412 The whitepoint reference, default is 2° D65.
1349
1413
13501414 Returns:
13511415 A grapefruit.Color instance.
1352
1416
13531417 >>> str(Color.NewFromCmyk(1, 0.32, 0, 0.5))
13541418 '(0, 0.34, 0.5, 1)'
13551419 >>> str(Color.NewFromCmyk(1, 0.32, 0, 0.5, 0.5))
13611425 @staticmethod
13621426 def NewFromHtml(html, alpha=1.0, wref=_DEFAULT_WREF):
13631427 '''Create a new instance based on the specifed HTML color definition.
1364
1428
13651429 Parameters:
13661430 :html:
13671431 The HTML definition of the color (#RRGGBB or #RGB or a color name).
13691433 The color transparency [0...1], default is opaque.
13701434 :wref:
13711435 The whitepoint reference, default is 2° D65.
1372
1436
13731437 Returns:
13741438 A grapefruit.Color instance.
1375
1439
13761440 >>> str(Color.NewFromHtml('#ff8000'))
13771441 '(1, 0.501961, 0, 1)'
13781442 >>> str(Color.NewFromHtml('ff8000'))
13851449 '(1, 0.980392, 0.803922, 1)'
13861450 >>> str(Color.NewFromHtml('#ff8000', 0.5))
13871451 '(1, 0.501961, 0, 0.5)'
1388
1452
13891453 '''
13901454 return Color(Color.HtmlToRgb(html), 'rgb', alpha, wref)
13911455
13921456 @staticmethod
13931457 def NewFromPil(pil, alpha=1.0, wref=_DEFAULT_WREF):
13941458 '''Create a new instance based on the specifed PIL color.
1395
1459
13961460 Parameters:
13971461 :pil:
13981462 A PIL compatible color representation (0xBBGGRR)
14001464 The color transparency [0...1], default is opaque
14011465 :wref:
14021466 The whitepoint reference, default is 2° D65.
1403
1467
14041468 Returns:
14051469 A grapefruit.Color instance.
1406
1470
14071471 >>> str(Color.NewFromPil(0x0080ff))
14081472 '(1, 0.501961, 0, 1)'
14091473 >>> str(Color.NewFromPil(0x0080ff, 0.5))
14101474 '(1, 0.501961, 0, 0.5)'
1411
1475
14121476 '''
14131477 return Color(Color.PilToRgb(pil), 'rgb', alpha, wref)
14141478
14151479 def __GetAlpha(self):
14161480 return self.__a
14171481 alpha = property(fget=__GetAlpha, doc='The transparency of this color. 0.0 is transparent and 1.0 is fully opaque.')
1418
1482
14191483 def __GetWRef(self):
14201484 return self.__wref
14211485 whiteRef = property(fget=__GetWRef, doc='the white reference point of this color.')
14231487 def __GetRGB(self):
14241488 return self.__rgb
14251489 rgb = property(fget=__GetRGB, doc='The RGB values of this Color.')
1426
1490
14271491 def __GetHue(self):
14281492 return self.__hsl[0]
14291493 hue = property(fget=__GetHue, doc='The hue of this color.')
14611525 return Color.CmyToCmyk(*Color.RgbToCmy(*self.__rgb))
14621526 cmyk = property(fget=__GetCMYK, doc='The CMYK values of this Color.')
14631527
1528 def __GetIntTuple(self):
1529 return Color.RgbToIntTuple(*self.__rgb)
1530 intTuple = property(fget=__GetIntTuple, doc='This Color as a tuple of integers in the range [0...255]')
1531
14641532 def __GetHTML(self):
14651533 return Color.RgbToHtml(*self.__rgb)
14661534 html = property(fget=__GetHTML, doc='This Color as an HTML color definition.')
14791547
14801548 def ColorWithAlpha(self, alpha):
14811549 '''Create a new instance based on this one with a new alpha value.
1482
1550
14831551 Parameters:
14841552 :alpha:
14851553 The transparency of the new color [0...1].
1486
1554
14871555 Returns:
14881556 A grapefruit.Color instance.
14891557
14901558 >>> Color.NewFromRgb(1.0, 0.5, 0.0, 1.0).ColorWithAlpha(0.5)
14911559 (1.0, 0.5, 0.0, 0.5)
1492
1560
14931561 '''
14941562 return Color(self.__rgb, 'rgb', alpha, self.__wref)
1495
1563
14961564 def ColorWithWhiteRef(self, wref, labAsRef=False):
14971565 '''Create a new instance based on this one with a new white reference.
1498
1566
14991567 Parameters:
15001568 :wref:
15011569 The whitepoint reference.
15021570 :labAsRef:
15031571 If True, the L*a*b* values of the current instance are used as reference
15041572 for the new color; otherwise, the RGB values are used as reference.
1505
1573
15061574 Returns:
15071575 A grapefruit.Color instance.
15081576
1509
1577
15101578 >>> c = Color.NewFromRgb(1.0, 0.5, 0.0, 1.0, Color.WHITE_REFERENCE['std_D65'])
1511
1579
15121580 >>> c2 = c.ColorWithWhiteRef(Color.WHITE_REFERENCE['sup_D50'])
15131581 >>> c2.rgb
15141582 (1.0, 0.5, 0.0)
15151583 >>> '(%g, %g, %g)' % c2.whiteRef
15161584 '(0.96721, 1, 0.81428)'
1517
1585
15181586 >>> c2 = c.ColorWithWhiteRef(Color.WHITE_REFERENCE['sup_D50'], labAsRef=True)
15191587 >>> '(%g, %g, %g)' % c2.rgb
15201588 '(1.01463, 0.490339, -0.148131)'
15341602
15351603 def ColorWithHue(self, hue):
15361604 '''Create a new instance based on this one with a new hue.
1537
1605
15381606 Parameters:
15391607 :hue:
15401608 The hue of the new color [0...360].
1541
1609
15421610 Returns:
15431611 A grapefruit.Color instance.
15441612
15461614 (1.0, 1.0, 0.0, 1.0)
15471615 >>> Color.NewFromHsl(30, 1, 0.5).ColorWithHue(60).hsl
15481616 (60, 1, 0.5)
1549
1617
15501618 '''
15511619 h, s, l = self.__hsl
15521620 return Color((hue, s, l), 'hsl', self.__a, self.__wref)
15531621
15541622 def ColorWithSaturation(self, saturation):
15551623 '''Create a new instance based on this one with a new saturation value.
1556
1624
15571625 .. note::
1558
1626
15591627 The saturation is defined for the HSL mode.
1560
1628
15611629 Parameters:
15621630 :saturation:
15631631 The saturation of the new color [0...1].
1564
1632
15651633 Returns:
15661634 A grapefruit.Color instance.
15671635
15691637 (0.75, 0.5, 0.25, 1.0)
15701638 >>> Color.NewFromHsl(30, 1, 0.5).ColorWithSaturation(0.5).hsl
15711639 (30, 0.5, 0.5)
1572
1640
15731641 '''
15741642 h, s, l = self.__hsl
15751643 return Color((h, saturation, l), 'hsl', self.__a, self.__wref)
15761644
15771645 def ColorWithLightness(self, lightness):
15781646 '''Create a new instance based on this one with a new lightness value.
1579
1647
15801648 Parameters:
15811649 :lightness:
15821650 The lightness of the new color [0...1].
1583
1651
15841652 Returns:
15851653 A grapefruit.Color instance.
15861654
15881656 (0.5, 0.25, 0.0, 1.0)
15891657 >>> Color.NewFromHsl(30, 1, 0.5).ColorWithLightness(0.25).hsl
15901658 (30, 1, 0.25)
1591
1659
15921660 '''
15931661 h, s, l = self.__hsl
15941662 return Color((h, s, lightness), 'hsl', self.__a, self.__wref)
15951663
15961664 def DarkerColor(self, level):
15971665 '''Create a new instance based on this one but darker.
1598
1666
15991667 Parameters:
16001668 :level:
16011669 The amount by which the color should be darkened to produce
16021670 the new one [0...1].
1603
1671
16041672 Returns:
16051673 A grapefruit.Color instance.
16061674
16081676 (0.5, 0.25, 0.0, 1.0)
16091677 >>> Color.NewFromHsl(30, 1, 0.5).DarkerColor(0.25).hsl
16101678 (30, 1, 0.25)
1611
1679
16121680 '''
16131681 h, s, l = self.__hsl
16141682 return Color((h, s, max(l - level, 0)), 'hsl', self.__a, self.__wref)
16151683
16161684 def LighterColor(self, level):
16171685 '''Create a new instance based on this one but lighter.
1618
1686
16191687 Parameters:
16201688 :level:
16211689 The amount by which the color should be lightened to produce
16221690 the new one [0...1].
1623
1691
16241692 Returns:
16251693 A grapefruit.Color instance.
16261694
16281696 (1.0, 0.75, 0.5, 1.0)
16291697 >>> Color.NewFromHsl(30, 1, 0.5).LighterColor(0.25).hsl
16301698 (30, 1, 0.75)
1631
1699
16321700 '''
16331701 h, s, l = self.__hsl
16341702 return Color((h, s, min(l + level, 1)), 'hsl', self.__a, self.__wref)
1635
1703
16361704 def Saturate(self, level):
16371705 '''Create a new instance based on this one but more saturated.
1638
1706
16391707 Parameters:
16401708 :level:
16411709 The amount by which the color should be saturated to produce
16421710 the new one [0...1].
1643
1711
16441712 Returns:
16451713 A grapefruit.Color instance.
16461714
16481716 (0.875, 0.5, 0.125, 1.0)
16491717 >>> Color.NewFromHsl(30, 0.5, 0.5).Saturate(0.25).hsl
16501718 (30, 0.75, 0.5)
1651
1719
16521720 '''
16531721 h, s, l = self.__hsl
16541722 return Color((h, min(s + level, 1), l), 'hsl', self.__a, self.__wref)
16551723
16561724 def Desaturate(self, level):
16571725 '''Create a new instance based on this one but less saturated.
1658
1726
16591727 Parameters:
16601728 :level:
16611729 The amount by which the color should be desaturated to produce
16621730 the new one [0...1].
1663
1731
16641732 Returns:
16651733 A grapefruit.Color instance.
16661734
16681736 (0.625, 0.5, 0.375, 1.0)
16691737 >>> Color.NewFromHsl(30, 0.5, 0.5).Desaturate(0.25).hsl
16701738 (30, 0.25, 0.5)
1671
1739
16721740 '''
16731741 h, s, l = self.__hsl
16741742 return Color((h, max(s - level, 0), l), 'hsl', self.__a, self.__wref)
1675
1743
16761744 def WebSafeDither(self):
16771745 '''Return the two websafe colors nearest to this one.
1678
1746
16791747 Returns:
16801748 A tuple of two grapefruit.Color instances which are the two
16811749 web safe colors closest this one.
16861754 '(1, 0.4, 0, 1)'
16871755 >>> str(c2)
16881756 '(1, 0.6, 0, 1)'
1689
1757
16901758 '''
16911759 return (
16921760 Color(Color.RgbToWebSafe(*self.__rgb), 'rgb', self.__a, self.__wref),
16941762
16951763 def Gradient(self, target, steps=100):
16961764 '''Create a list with the gradient colors between this and the other color.
1697
1765
16981766 Parameters:
16991767 :target:
17001768 The grapefruit.Color at the other end of the gradient.
17011769 :steps:
17021770 The number of gradients steps to create.
1703
1704
1771
1772
17051773 Returns:
17061774 A list of grapefruit.Color instances.
17071775
17091777 >>> c2 = Color.NewFromRgb(0.0, 1.0, 0.0, alpha=0)
17101778 >>> c1.Gradient(c2, 3)
17111779 [(0.75, 0.25, 0.0, 0.75), (0.5, 0.5, 0.0, 0.5), (0.25, 0.75, 0.0, 0.25)]
1712
1780
17131781 '''
17141782 gradient = []
17151783 rgba1 = self.__rgb + (self.__a,)
17161784 rgba2 = target.__rgb + (target.__a,)
1717
1785
17181786 steps += 1
1719 for n in xrange(1, steps):
1787 for n in range(1, steps):
17201788 d = 1.0*n/steps
17211789 r = (rgba1[0]*(1-d)) + (rgba2[0]*d)
17221790 g = (rgba1[1]*(1-d)) + (rgba2[1]*d)
17241792 a = (rgba1[3]*(1-d)) + (rgba2[3]*d)
17251793
17261794 gradient.append(Color((r, g, b), 'rgb', a, self.__wref))
1727
1795
17281796 return gradient
17291797
17301798 def ComplementaryColor(self, mode='ryb'):
17311799 '''Create a new instance which is the complementary color of this one.
1732
1800
17331801 Parameters:
17341802 :mode:
17351803 Select which color wheel to use for the generation (ryb/rgb).
1736
1737
1804
1805
17381806 Returns:
17391807 A grapefruit.Color instance.
17401808
1741 >>> Color.NewFromHsl(30, 1, 0.5).ComplementaryColor()
1809 >>> Color.NewFromHsl(30, 1, 0.5).ComplementaryColor(mode='rgb')
17421810 (0.0, 0.5, 1.0, 1.0)
1743 >>> Color.NewFromHsl(30, 1, 0.5).ComplementaryColor().hsl
1811 >>> Color.NewFromHsl(30, 1, 0.5).ComplementaryColor(mode='rgb').hsl
17441812 (210, 1, 0.5)
1745
1813
17461814 '''
17471815 h, s, l = self.__hsl
17481816
17491817 if mode == 'ryb': h = Color.RgbToRyb(h)
17501818 h = (h+180)%360
17511819 if mode == 'ryb': h = Color.RybToRgb(h)
1752
1820
17531821 return Color((h, s, l), 'hsl', self.__a, self.__wref)
1754
1822
17551823 def MonochromeScheme(self):
17561824 '''Return 4 colors in the same hue with varying saturation/lightness.
1757
1825
17581826 Returns:
17591827 A tuple of 4 grapefruit.Color in the same hue as this one,
17601828 with varying saturation/lightness.
17691837 else: return x-min
17701838
17711839 h, s, l = self.__hsl
1772
1840
17731841 s1 = _wrap(s, 0.3, 0.1, 0.3)
17741842 l1 = _wrap(l, 0.5, 0.2, 0.3)
1775
1843
17761844 s2 = s
17771845 l2 = _wrap(l, 0.2, 0.2, 0.6)
1778
1846
17791847 s3 = s1
17801848 l3 = max(0.2, l + (1-l)*0.2)
1781
1849
17821850 s4 = s
17831851 l4 = _wrap(l, 0.5, 0.2, 0.3)
1784
1852
17851853 return (
17861854 Color((h, s1, l1), 'hsl', self.__a, self.__wref),
17871855 Color((h, s2, l2), 'hsl', self.__a, self.__wref),
17881856 Color((h, s3, l3), 'hsl', self.__a, self.__wref),
17891857 Color((h, s4, l4), 'hsl', self.__a, self.__wref))
1790
1858
17911859 def TriadicScheme(self, angle=120, mode='ryb'):
17921860 '''Return two colors forming a triad or a split complementary with this one.
1793
1861
17941862 Parameters:
17951863 :angle:
17961864 The angle between the hues of the created colors.
17971865 The default value makes a triad.
17981866 :mode:
17991867 Select which color wheel to use for the generation (ryb/rgb).
1800
1868
18011869 Returns:
18021870 A tuple of two grapefruit.Color forming a color triad with
18031871 this one or a split complementary.
18041872
18051873 >>> c1 = Color.NewFromHsl(30, 1, 0.5)
1806
1807 >>> c2, c3 = c1.TriadicScheme()
1874
1875 >>> c2, c3 = c1.TriadicScheme(mode='rgb')
18081876 >>> c2.hsl
18091877 (150.0, 1, 0.5)
18101878 >>> c3.hsl
18111879 (270.0, 1, 0.5)
1812
1813 >>> c2, c3 = c1.TriadicScheme(40)
1880
1881 >>> c2, c3 = c1.TriadicScheme(angle=40, mode='rgb')
18141882 >>> c2.hsl
18151883 (190.0, 1, 0.5)
18161884 >>> c3.hsl
18171885 (230.0, 1, 0.5)
1818
1886
18191887 '''
18201888 h, s, l = self.__hsl
18211889 angle = min(angle, 120) / 2.0
1822
1890
18231891 if mode == 'ryb': h = Color.RgbToRyb(h)
18241892 h += 180
18251893 h1 = (h - angle) % 360
18271895 if mode == 'ryb':
18281896 h1 = Color.RybToRgb(h1)
18291897 h2 = Color.RybToRgb(h2)
1830
1898
18311899 return (
18321900 Color((h1, s, l), 'hsl', self.__a, self.__wref),
18331901 Color((h2, s, l), 'hsl', self.__a, self.__wref))
18341902
18351903 def TetradicScheme(self, angle=30, mode='ryb'):
18361904 '''Return three colors froming a tetrad with this one.
1837
1905
18381906 Parameters:
18391907 :angle:
18401908 The angle to substract from the adjacent colors hues [-90...90].
18411909 You can use an angle of zero to generate a square tetrad.
18421910 :mode:
18431911 Select which color wheel to use for the generation (ryb/rgb).
1844
1912
18451913 Returns:
18461914 A tuple of three grapefruit.Color forming a color tetrad with
18471915 this one.
18491917 >>> col = Color.NewFromHsl(30, 1, 0.5)
18501918 >>> [c.hsl for c in col.TetradicScheme(mode='rgb', angle=30)]
18511919 [(90, 1, 0.5), (210, 1, 0.5), (270, 1, 0.5)]
1852
1920
18531921 '''
18541922 h, s, l = self.__hsl
18551923
18691937
18701938 def AnalogousScheme(self, angle=30, mode='ryb'):
18711939 '''Return two colors analogous to this one.
1872
1940
18731941 Args:
18741942 :angle:
18751943 The angle between the hues of the created colors and this one.
18801948 A tuple of grapefruit.Colors analogous to this one.
18811949
18821950 >>> c1 = Color.NewFromHsl(30, 1, 0.5)
1883
1884 >>> c2, c3 = c1.AnalogousScheme()
1951
1952 >>> c2, c3 = c1.AnalogousScheme(angle=60, mode='rgb')
18851953 >>> c2.hsl
18861954 (330, 1, 0.5)
18871955 >>> c3.hsl
18881956 (90, 1, 0.5)
1889
1890 >>> c2, c3 = c1.AnalogousScheme(10)
1957
1958 >>> c2, c3 = c1.AnalogousScheme(angle=10, mode='rgb')
18911959 >>> c2.hsl
18921960 (20, 1, 0.5)
18931961 >>> c3.hsl
18941962 (40, 1, 0.5)
1895
1963
18961964 '''
18971965 h, s, l = self.__hsl
18981966
19031971 if mode == 'ryb':
19041972 h1 = Color.RybToRgb(h1)
19051973 h2 = Color.RybToRgb(h2)
1906
1974
19071975 return (Color((h1, s, l), 'hsl', self.__a, self.__wref),
19081976 Color((h2, s, l), 'hsl', self.__a, self.__wref))
19091977
19101978 def AlphaBlend(self, other):
19111979 '''Alpha-blend this color on the other one.
1912
1980
19131981 Args:
19141982 :other:
19151983 The grapefruit.Color to alpha-blend with this one.
1916
1984
19171985 Returns:
19181986 A grapefruit.Color instance which is the result of alpha-blending
19191987 this color on the other one.
19231991 >>> c3 = c1.AlphaBlend(c2)
19241992 >>> str(c3)
19251993 '(1, 0.875, 0.75, 0.84)'
1926
1994
19271995 '''
19281996 # get final alpha channel
19291997 fa = self.__a + other.__a - (self.__a * other.__a)
19372005
19382006 sr, sg, sb = [v * sa for v in self.__rgb]
19392007 dr, dg, db = [v * da for v in other.__rgb]
1940
2008
19412009 return Color((sr+dr, sg+dg, sb+db), 'rgb', fa, self.__wref)
19422010
19432011 def Blend(self, other, percent=0.5):
19462014 Args:
19472015 :other:
19482016 the grapefruit.Color to blend with this one.
1949
2017
19502018 Returns:
19512019 A grapefruit.Color instance which is the result of blending
19522020 this color on the other one.
19562024 >>> c3 = c1.Blend(c2)
19572025 >>> str(c3)
19582026 '(1, 0.75, 0.5, 0.4)'
1959
2027
19602028 '''
19612029 dest = 1.0 - percent
19622030 rgb = tuple(((u * percent) + (v * dest) for u, v in zip(self.__rgb, other.__rgb)))
19702038
19712039 if __name__=='__main__':
19722040 _test()
2041
2042 # vim: ts=2 sts=2 sw=2 et
0 #!/usr/bin/python
1 # -*- coding: utf-8 -*-#
2
3 # Copyright (c) 2008, Xavier Basty
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 '''Unit tests for the grapefruit module.'''
18
19 # $Id: grapefruit_test.py 24 2008-05-25 16:23:22Z xbasty $
20 __author__ = 'xbasty@gmail.com'
21 __version__ = '0.1a3'
22
23 import unittest
24 import grapefruit
25
26 class GrapeFruitTestCase(unittest.TestCase):
27 def failUnlessNear(self, first, second, diff=9e-5, msg=None):
28 '''
29 Fail if the difference between the two objects is greater
30 than a certain amout (default 9e-5).
31 '''
32 if hasattr(first,'__iter__') and hasattr(second,'__iter__'):
33 if len(first) != len(second):
34 raise self.failureException, (msg or "%r != %r" % (first, second))
35
36 for f, s in zip(first, second):
37 if abs(s-f) > diff:
38 raise self.failureException, (msg or "%r != %r @ %f" % (first, second, diff))
39 elif abs(second-first) > diff:
40 raise self.failureException, (msg or "%r != %r @ %f" % (first, second, diff))
41 assertNear = failUnlessNear
42
43 class ConversionTest(GrapeFruitTestCase):
44 '''Test the static color conversion methods.'''
45
46 def testRgbHsl(self):
47 self.assertNear((30.0, 1.0, 0.5), grapefruit.Color.RgbToHsl(1, 0.5, 0))
48 self.assertNear((20.0, 1.0, 0.625), grapefruit.Color.RgbToHsl(1, 0.5, 0.25)) #ff8040
49 self.assertNear((40.0, 1.0, 0.375), grapefruit.Color.RgbToHsl(0.75, 0.5, 0)) #bf8000
50
51 self.assertNear((1, 0.5, 0), grapefruit.Color.HslToRgb(30.0, 1.0, 0.5))
52 self.assertNear((1, 0.5, 0.25), grapefruit.Color.HslToRgb(20.0, 1.0, 0.625))
53 self.assertNear((0.75, 0.5, 0), grapefruit.Color.HslToRgb(40.0, 1.0, 0.375))
54
55 def testRgbHsv(self):
56 self.assertEqual((30.0, 1.0, 1.0), grapefruit.Color.RgbToHsv(1, 0.5, 0))
57 self.assertEqual((1, 0.5, 0), grapefruit.Color.HsvToRgb(30.0, 1.0, 1.0))
58
59 def testRgbYiq(self):
60 self.assertNear((0.5923, 0.4589, -0.05), grapefruit.Color.RgbToYiq(1, 0.5, 0))
61 self.assertNear((1, 0.5, 0), grapefruit.Color.YiqToRgb(0.5923, 0.4589, -0.05))
62
63 def testRgbYuv(self):
64 self.assertNear((0.5925, -0.2916, 0.3575), grapefruit.Color.RgbToYuv(1, 0.5, 0))
65 self.assertNear((1, 0.5, 0), grapefruit.Color.YuvToRgb(0.5925, -0.2916, 0.3575))
66
67 def testRgbXyz(self):
68 self.assertNear((0.4890, 0.3657, 0.04485), grapefruit.Color.RgbToXyz(1, 0.5, 0))
69 self.assertNear((1, 0.5, 0), grapefruit.Color.XyzToRgb(0.488941, 0.365682, 0.0448137))
70
71 def testXyzLab(self):
72 self.assertNear((66.9518, 0.4308, 0.7397), grapefruit.Color.XyzToLab(0.488941, 0.365682, 0.0448137))
73 self.assertNear((0.4890, 0.3657, 0.0449), grapefruit.Color.LabToXyz(66.9518, 0.4308, 0.7397))
74 self.assertNear((66.9518, 0.4117, 0.6728), grapefruit.Color.XyzToLab(0.488941, 0.365682, 0.0448137, grapefruit.Color.WHITE_REFERENCE["std_D50"]))
75 self.assertNear((0.4890, 0.3657, 0.0449), grapefruit.Color.LabToXyz(66.9518, 0.4117, 0.6728, grapefruit.Color.WHITE_REFERENCE["std_D50"]))
76
77 def testCmykCmy(self):
78 self.assertNear((1, 0.32, 0, 0.5), grapefruit.Color.CmyToCmyk(1.0, 0.66, 0.5))
79 self.assertNear((1.0, 0.66, 0.5), grapefruit.Color.CmykToCmy(1, 0.32, 0, 0.5))
80
81 def testRgbCmy(self):
82 self.assertEqual((0, 0.5, 1), grapefruit.Color.RgbToCmy(1, 0.5, 0))
83 self.assertEqual((1, 0.5, 0), grapefruit.Color.CmyToRgb(0, 0.5, 1))
84
85 def testRgbHtml(self):
86 self.assertEqual("#ff8000", grapefruit.Color.RgbToHtml(1, 0.5, 0))
87 self.assertNear((1.0, 0.5020, 0.0), grapefruit.Color.HtmlToRgb("#ff8000"))
88 self.assertNear((1.0, 0.5020, 0.0), grapefruit.Color.HtmlToRgb("ff8000"))
89 self.assertNear((1.0, 0.4, 0.0), grapefruit.Color.HtmlToRgb("#f60"))
90 self.assertNear((1.0, 0.4, 0.0), grapefruit.Color.HtmlToRgb("f60"))
91 self.assertNear((1.000000, 0.980392, 0.803922), grapefruit.Color.HtmlToRgb("lemonchiffon"))
92
93 def testRgbPil(self):
94 self.assertNear(0x0080ff, grapefruit.Color.RgbToPil(1, 0.5, 0))
95 self.assertNear((1.0, 0.5020, 0), grapefruit.Color.PilToRgb(0x0080ff))
96
97 def testWebSafeComponent(self):
98 self.assertEqual(0.2, grapefruit.Color._WebSafeComponent(0.2))
99 self.assertEqual(0.2, grapefruit.Color._WebSafeComponent(0.25))
100 self.assertEqual(0.4, grapefruit.Color._WebSafeComponent(0.3))
101 self.assertEqual(0.4, grapefruit.Color._WebSafeComponent(0.25, True))
102 self.assertEqual(0.2, grapefruit.Color._WebSafeComponent(0.2, True))
103 self.assertEqual(0.2, grapefruit.Color._WebSafeComponent(0.3, True))
104
105 def testRgbToWebSafe(self):
106 self.assertEqual((1.0, 0.6, 0.0), grapefruit.Color.RgbToWebSafe(1, 0.55, 0.0))
107 self.assertEqual((1.0, 0.4, 0.0), grapefruit.Color.RgbToWebSafe(1, 0.55, 0.0, True))
108 self.assertEqual((1.0, 0.4, 0.0), grapefruit.Color.RgbToWebSafe(1, 0.5, 0.0, True))
109
110 def testRgbToGreyscale(self):
111 self.assertEqual((0.6, 0.6, 0.6), grapefruit.Color.RgbToGreyscale(1, 0.8, 0))
112
113 class NewFromTest(GrapeFruitTestCase):
114 '''Test the static color instanciation methods.'''
115 def testNewFromRgb(self):
116 c = grapefruit.Color.NewFromRgb(1.0, 0.5, 0.0)
117 self.assertEqual(c, (1.0, 0.5, 0.0, 1.0))
118 c = grapefruit.Color.NewFromRgb(1.0, 0.5, 0.0, 0.5)
119 self.assertEqual(c, (1.0, 0.5, 0.0, 0.5))
120
121 def testNewFromHsl(self):
122 c = grapefruit.Color.NewFromHsl(30, 1, 0.5)
123 self.assertEqual(c, (1.0, 0.5, 0.0, 1.0))
124 c = grapefruit.Color.NewFromHsl(30, 1, 0.5, 0.5)
125 self.assertEqual(c, (1.0, 0.5, 0.0, 0.5))
126
127 def testNewFromHsv(self):
128 c = grapefruit.Color.NewFromHsv(30, 1, 1)
129 self.assertEqual(c, (1.0, 0.5, 0.0, 1.0))
130 c = grapefruit.Color.NewFromHsv(30, 1, 1, 0.5)
131 self.assertEqual(c, (1.0, 0.5, 0.0, 0.5))
132
133 def testNewFromYiq(self):
134 c = grapefruit.Color.NewFromYiq(0.5923, 0.4589, -0.0499818)
135 self.assertNear(c, (1, 0.5, 0, 1))
136 c = grapefruit.Color.NewFromYiq(0.5923, 0.4589,-0.05, 0.5)
137 self.assertNear(c, (1, 0.5, 0, 0.5))
138
139 def testNewFromYuv(self):
140 c = grapefruit.Color.NewFromYuv(0.5925, -0.2916, 0.3575)
141 self.assertNear(c, (1, 0.5, 0, 1))
142 c = grapefruit.Color.NewFromYuv(0.5925, -0.2916, 0.3575, 0.5)
143 self.assertNear(c, (1, 0.5, 0, 0.5))
144
145 def testNewFromXyz(self):
146 c = grapefruit.Color.NewFromXyz(0.488941, 0.365682, 0.0448137)
147 self.assertNear(c, (1, 0.5, 0, 1))
148 c = grapefruit.Color.NewFromXyz(0.488941, 0.365682, 0.0448137, 0.5)
149 self.assertNear(c, (1, 0.5, 0, 0.5))
150
151 def testNewFromLab(self):
152 c = grapefruit.Color.NewFromLab(66.9518, 0.43084, 0.739692)
153 self.assertNear(c, (1, 0.5, 0, 1))
154 c = grapefruit.Color.NewFromLab(66.9518, 0.43084, 0.739692, wref=grapefruit.Color.WHITE_REFERENCE["std_D50"])
155 self.assertNear(c, (1.0123754, 0.492012, -0.143110, 1))
156 c = grapefruit.Color.NewFromLab(66.9518, 0.43084, 0.739692, 0.5)
157 self.assertNear(c, (1, 0.5, 0, 0.5))
158 c = grapefruit.Color.NewFromLab(66.9518, 0.43084, 0.739692, 0.5, grapefruit.Color.WHITE_REFERENCE["std_D50"])
159 self.assertNear(c, (1.0123754, 0.492012, -0.143110, 0.5))
160
161 def testNewFromCmy(self):
162 c = grapefruit.Color.NewFromCmy(0, 0.5, 1)
163 self.assertEqual(c, (1, 0.5, 0, 1.0))
164 c = grapefruit.Color.NewFromCmy(0, 0.5, 1, 0.5)
165 self.assertEqual(c, (1, 0.5, 0, 0.5))
166
167 def testNewFromCmyk(self):
168 c = grapefruit.Color.NewFromCmyk(1, 0.32, 0, 0.5)
169 self.assertNear(c, (0, 0.34, 0.5, 1))
170 c = grapefruit.Color.NewFromCmyk(1, 0.32, 0, 0.5, 0.5)
171 self.assertNear(c, (0, 0.34, 0.5, 0.5))
172
173 def testNewFromHtml(self):
174 c = grapefruit.Color.NewFromHtml("#ff8000")
175 self.assertNear(c, (1, 0.5020, 0, 1))
176 c = grapefruit.Color.NewFromHtml("ff8000")
177 self.assertNear(c, (1, 0.5020, 0, 1))
178 c = grapefruit.Color.NewFromHtml("#f60")
179 self.assertNear(c, (1, 0.4, 0, 1))
180 c = grapefruit.Color.NewFromHtml("f60")
181 self.assertNear(c, (1, 0.4, 0, 1))
182 c = grapefruit.Color.NewFromHtml("lemonchiffon")
183 self.assertNear(c, (1, 0.9804, 0.8039, 1))
184 c = grapefruit.Color.NewFromHtml("#ff8000", 0.5)
185 self.assertNear(c, (1, 0.5020, 0, 0.5))
186
187 def testNewFromPil(self):
188 c = grapefruit.Color.NewFromPil(0x0080ff)
189 self.assertNear(c, (1, 0.5020, 0, 1))
190 c = grapefruit.Color.NewFromPil(0x0080ff, 0.5)
191 self.assertNear(c, (1, 0.5020, 0, 0.5))
192
193
194 class ColorTest(GrapeFruitTestCase):
195 def setUp(self):
196 self.rgbCol = grapefruit.Color.NewFromRgb(1.0, 0.5, 0.0)
197 self.hslCol = grapefruit.Color.NewFromHsl(30, 1, 0.5)
198 self.hslCol2 = grapefruit.Color.NewFromHsl(30, 0.5, 0.5)
199
200 def testInit(self):
201 self.assertEqual(grapefruit.Color((1.0, 0.5, 0.0)), (1.0, 0.5, 0.0, 1.0))
202 self.assertEqual(grapefruit.Color((1.0, 0.5, 0.0), mode='rgb'), (1.0, 0.5, 0.0, 1.0))
203 self.assertEqual(grapefruit.Color((30, 1, 0.5), mode='hsl'), (1.0, 0.5, 0.0, 1.0))
204
205 self.assertRaises(ValueError, grapefruit.Color, (30, 1, 0.5), 'hsv')
206
207 def testEq(self):
208 self.assertEqual(self.rgbCol, self.hslCol)
209 self.assertEqual(self.rgbCol, (1.0, 0.5, 0.0, 1.0))
210 self.assertEqual(self.rgbCol, [1.0, 0.5, 0.0, 1.0])
211 self.assertEqual([1.0, 0.5, 0.0, 1.0], self.rgbCol)
212 self.assertNotEqual(self.rgbCol, '(1.0, 0.5, 0.0, 1.0)')
213
214 def testRepr(self):
215 self.assertEqual(repr(self.rgbCol), '(1.0, 0.5, 0.0, 1.0)')
216 self.assertEqual(repr(self.hslCol), '(1.0, 0.5, 0.0, 1.0)')
217
218 def testStr(self):
219 self.assertEqual(str(self.rgbCol), '(1, 0.5, 0, 1)')
220 self.assertEqual(str(self.hslCol), '(1, 0.5, 0, 1)')
221
222 def testIter(self):
223 self.assertEqual([1, 0.5, 0, 1], list(iter(self.rgbCol)))
224
225 def testProperties(self):
226 self.assertEqual(self.rgbCol.alpha, 1.0)
227 self.assertEqual(self.rgbCol.whiteRef, grapefruit.Color.WHITE_REFERENCE['std_D65'])
228 self.assertEqual(self.rgbCol.rgb, (1, 0.5, 0))
229 self.assertEqual(self.hslCol.hue, 30)
230 self.assertEqual(self.rgbCol.hsl, (30, 1, 0.5))
231 self.assertEqual(self.rgbCol.hsv, (30, 1, 1))
232 self.assertNear(self.rgbCol.yiq, (0.5923, 0.4589, -0.05))
233 self.assertNear(self.rgbCol.yuv, (0.5925, -0.2916, 0.3575))
234 self.assertNear(self.rgbCol.xyz, (0.4890, 0.3657, 0.04485))
235 self.assertNear(self.rgbCol.lab, (66.9518, 0.4308, 0.7397))
236 self.assertEqual(self.rgbCol.cmy, (0, 0.5, 1))
237 self.assertEqual(self.rgbCol.cmyk, (0, 0.5, 1, 0))
238 self.assertEqual(self.rgbCol.html, '#ff8000')
239 self.assertEqual(self.rgbCol.pil, 0x0080ff)
240 self.assertEqual(self.rgbCol.webSafe, (1, 0.6, 0))
241 self.assertEqual(self.rgbCol.greyscale, (0.5, 0.5, 0.5))
242
243 c = grapefruit.Color.NewFromRgb(1, 0.5, 0, wref=grapefruit.Color.WHITE_REFERENCE['std_D50'])
244 self.assertNear(c.lab, (66.9518, 0.4117, 0.6728))
245
246 def testColorWitgAlpha(self):
247 self.assertEqual(self.rgbCol.ColorWithAlpha(0.5), (1, 0.5, 0, 0.5))
248
249 def testColorWithWhiteRef(self):
250 self.assertEqual(self.hslCol.ColorWithWhiteRef((0.1, 0.2, 0.3)).whiteRef, (0.1, 0.2, 0.3))
251
252 def testColorWithHue(self):
253 self.assertEqual(self.hslCol.ColorWithHue(60), (1.0, 1.0, 0.0, 1.0))
254 self.assertEqual(self.hslCol.ColorWithHue(60).hsl, (60, 1, 0.5))
255
256 def testColorWithSaturation(self):
257 self.assertEqual(self.hslCol.ColorWithSaturation(0.5), (0.75, 0.5, 0.25, 1.0))
258 self.assertEqual(self.hslCol.ColorWithSaturation(0.5).hsl, (30, 0.5, 0.5))
259
260 def testColorWithLightness(self):
261 self.assertEqual(self.hslCol.ColorWithLightness(1), (1.0, 1.0, 1.0, 1.0))
262 self.assertEqual(self.hslCol.ColorWithLightness(1).hsl, (30, 1.0, 1.0))
263
264 def testDarkerColor(self):
265 self.assertNear(self.hslCol.DarkerColor(0.2), (0.6, 0.3, 0.0, 1.0))
266 self.assertNear(self.hslCol.DarkerColor(0.2).hsl, (30, 1, 0.3))
267
268 def testLighterColor(self):
269 self.assertNear(self.hslCol.LighterColor(0.2), (1.0, 0.7, 0.4, 1.0))
270 self.assertNear(self.hslCol.LighterColor(0.2).hsl, (30, 1, 0.7))
271
272 def testSaturate(self):
273 self.assertNear(self.hslCol2.Saturate(0.25), (0.875, 0.5, 0.125, 1.0))
274 self.assertNear(self.hslCol2.Saturate(0.25).hsl, (30, 0.75, 0.5))
275
276 def testDesaturate(self):
277 self.assertNear(self.hslCol2.Desaturate(0.25), (0.625, 0.5, 0.375, 1.0))
278 self.assertNear(self.hslCol2.Desaturate(0.25).hsl, (30, 0.25, 0.5))
279
280 def testWebSafeDither(self):
281 dithered = (
282 (1.0, 0.6, 0.0, 1.0),
283 (1.0, 0.4, 0.0, 1.0))
284 self.assertEqual(self.rgbCol.WebSafeDither(), dithered)
285
286 def testGradient(self):
287 gradient = [
288 (0.75, 0.25, 0.0, 1.0),
289 (0.5, 0.5, 0.0, 1.0),
290 (0.25, 0.75, 0.0, 1.0)]
291 c1 = grapefruit.Color.NewFromRgb(1.0, 0.0, 0.0)
292 c2 = grapefruit.Color.NewFromRgb(0.0, 1.0, 0.0)
293 self.assertEqual(gradient, c1.Gradient(c2, 3))
294
295 def testComplementaryColor(self):
296 self.assertEqual(self.hslCol.ComplementaryColor(mode='rgb').hsl, (210, 1, 0.5))
297
298 def testMonochromeScheme(self):
299 monochrome = (
300 (0.94, 0.8, 0.66, 1.0), # hsl(30, 0.7, 0.8)
301 (0.6, 0.3, 0.0, 1.0), # hsl(30, 1, 0.3)
302 (0.88, 0.6, 0.32, 1.0), # hsl(30, 0.7, 0.6)
303 (1.0, 0.8, 0.6, 1.0)) # hsl(30, 1, 0.8)
304 scheme = self.rgbCol.MonochromeScheme()
305 for i in xrange(len(monochrome)):
306 self.assertNear(scheme[i], monochrome[i])
307
308 def testTriadicScheme(self):
309 triad = (
310 (0.0, 1.0, 0.5, 1.0),
311 (0.5, 0.0, 1.0, 1.0))
312 self.assertEqual(self.rgbCol.TriadicScheme(mode='rgb'), triad)
313
314 def testTetradicScheme(self):
315 tetrad = (
316 (0.5, 1.0, 0.0, 1.0),
317 (0.0, 0.5, 1.0, 1.0),
318 (0.5, 0.0, 1.0, 1.0))
319 self.assertEqual(self.rgbCol.TetradicScheme(mode='rgb'), tetrad)
320
321 def testAnalogousScheme(self):
322 scheme = (
323 (1.0, 0.0, 0.0, 1.0),
324 (1.0, 1.0, 0.0, 1.0))
325 self.assertEqual(self.rgbCol.AnalogousScheme(mode='rgb'), scheme)
326
327 def testAlphaBlend(self):
328 c1 = grapefruit.Color.NewFromRgb(1, 0.5, 0, alpha = 0.2)
329 c2 = grapefruit.Color.NewFromRgb(1, 1, 1, alpha = 0.8)
330 self.assertNear(c1.AlphaBlend(c2), (1, 0.875, 0.75, 0.84))
331
332 def testBlend(self):
333 c1 = grapefruit.Color.NewFromRgb(1, 0.5, 0, alpha = 0.2)
334 c2 = grapefruit.Color.NewFromRgb(1, 1, 1, alpha = 0.6)
335 self.assertEqual(c1.Blend(c2), (1, 0.75, 0.5, 0.4))
336
337
338 if __name__ == '__main__':
339 unittest.main()
340 pass
0 #!/usr/bin/python
1 # -*- coding: utf-8 -*-#
2
3 # Copyright (c) 2008, Xavier Basty
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 '''Unit tests for the grapefruit module.'''
18
19 # $Id$
20 __author__ = 'xbasty@gmail.com'
21 __version__ = '0.1a3'
22
23 import unittest
24 import doctest
25 import grapefruit
26
27 # Also run doctests.
28 def load_tests(loader, tests, ignore):
29 tests.addTests(doctest.DocTestSuite(grapefruit))
30 return tests
31
32
33 class GrapeFruitTestCase(unittest.TestCase):
34 def failUnlessNear(self, first, second, diff=9e-5, msg=None):
35 '''
36 Fail if the difference between the two objects is greater
37 than a certain amout (default 9e-5).
38 '''
39 if hasattr(first,'__iter__') and hasattr(second,'__iter__'):
40 if len(first) != len(second):
41 raise self.failureException(msg or "%r != %r" % (first, second))
42
43 for f, s in zip(first, second):
44 if abs(s-f) > diff:
45 raise self.failureException(msg or "%r != %r @ %f" % (first, second, diff))
46 elif abs(second-first) > diff:
47 raise self.failureException(msg or "%r != %r @ %f" % (first, second, diff))
48 assertNear = failUnlessNear
49
50 class ConversionTest(GrapeFruitTestCase):
51 '''Test the static color conversion methods.'''
52
53 def testRgbHsl(self):
54 self.assertNear((30.0, 1.0, 0.5), grapefruit.Color.RgbToHsl(1, 0.5, 0))
55 self.assertNear((20.0, 1.0, 0.625), grapefruit.Color.RgbToHsl(1, 0.5, 0.25)) #ff8040
56 self.assertNear((40.0, 1.0, 0.375), grapefruit.Color.RgbToHsl(0.75, 0.5, 0)) #bf8000
57
58 self.assertNear((1, 0.5, 0), grapefruit.Color.HslToRgb(30.0, 1.0, 0.5))
59 self.assertNear((1, 0.5, 0.25), grapefruit.Color.HslToRgb(20.0, 1.0, 0.625))
60 self.assertNear((0.75, 0.5, 0), grapefruit.Color.HslToRgb(40.0, 1.0, 0.375))
61
62 def testRgbHsv(self):
63 self.assertEqual((30.0, 1.0, 1.0), grapefruit.Color.RgbToHsv(1, 0.5, 0))
64 self.assertEqual((1, 0.5, 0), grapefruit.Color.HsvToRgb(30.0, 1.0, 1.0))
65
66 def testRgbYiq(self):
67 self.assertNear((0.5923, 0.4589, -0.05), grapefruit.Color.RgbToYiq(1, 0.5, 0))
68 self.assertNear((1, 0.5, 0), grapefruit.Color.YiqToRgb(0.5923, 0.4589, -0.05))
69
70 def testRgbYuv(self):
71 self.assertNear((0.5925, -0.2916, 0.3575), grapefruit.Color.RgbToYuv(1, 0.5, 0))
72 self.assertNear((1, 0.5, 0), grapefruit.Color.YuvToRgb(0.5925, -0.2916, 0.3575))
73
74 def testRgbXyz(self):
75 self.assertNear((0.4890, 0.3657, 0.04485), grapefruit.Color.RgbToXyz(1, 0.5, 0))
76 self.assertNear((1, 0.5, 0), grapefruit.Color.XyzToRgb(0.488941, 0.365682, 0.0448137))
77
78 def testXyzLab(self):
79 self.assertNear((66.9518, 0.4308, 0.7397), grapefruit.Color.XyzToLab(0.488941, 0.365682, 0.0448137))
80 self.assertNear((0.4890, 0.3657, 0.0449), grapefruit.Color.LabToXyz(66.9518, 0.4308, 0.7397))
81 self.assertNear((66.9518, 0.4117, 0.6728), grapefruit.Color.XyzToLab(0.488941, 0.365682, 0.0448137, grapefruit.Color.WHITE_REFERENCE["std_D50"]))
82 self.assertNear((0.4890, 0.3657, 0.0449), grapefruit.Color.LabToXyz(66.9518, 0.4117, 0.6728, grapefruit.Color.WHITE_REFERENCE["std_D50"]))
83
84 def testCmykCmy(self):
85 self.assertNear((1, 0.32, 0, 0.5), grapefruit.Color.CmyToCmyk(1.0, 0.66, 0.5))
86 self.assertNear((1.0, 0.66, 0.5), grapefruit.Color.CmykToCmy(1, 0.32, 0, 0.5))
87
88 def testRgbCmy(self):
89 self.assertEqual((0, 0.5, 1), grapefruit.Color.RgbToCmy(1, 0.5, 0))
90 self.assertEqual((1, 0.5, 0), grapefruit.Color.CmyToRgb(0, 0.5, 1))
91
92 def testRgbHtml(self):
93 self.assertEqual("#ff8000", grapefruit.Color.RgbToHtml(1, 0.5, 0))
94 self.assertNear((1.0, 0.5020, 0.0), grapefruit.Color.HtmlToRgb("#ff8000"))
95 self.assertNear((1.0, 0.5020, 0.0), grapefruit.Color.HtmlToRgb("ff8000"))
96 self.assertNear((1.0, 0.4, 0.0), grapefruit.Color.HtmlToRgb("#f60"))
97 self.assertNear((1.0, 0.4, 0.0), grapefruit.Color.HtmlToRgb("f60"))
98 self.assertNear((1.000000, 0.980392, 0.803922), grapefruit.Color.HtmlToRgb("lemonchiffon"))
99
100 def testRgbPil(self):
101 self.assertNear(0x0080ff, grapefruit.Color.RgbToPil(1, 0.5, 0))
102 self.assertNear((1.0, 0.5020, 0), grapefruit.Color.PilToRgb(0x0080ff))
103
104 def testWebSafeComponent(self):
105 self.assertEqual(0.2, grapefruit.Color._WebSafeComponent(0.2))
106 self.assertEqual(0.2, grapefruit.Color._WebSafeComponent(0.25))
107 self.assertEqual(0.4, grapefruit.Color._WebSafeComponent(0.3))
108 self.assertEqual(0.4, grapefruit.Color._WebSafeComponent(0.25, True))
109 self.assertEqual(0.2, grapefruit.Color._WebSafeComponent(0.2, True))
110 self.assertEqual(0.2, grapefruit.Color._WebSafeComponent(0.3, True))
111
112 def testRgbToWebSafe(self):
113 self.assertEqual((1.0, 0.6, 0.0), grapefruit.Color.RgbToWebSafe(1, 0.55, 0.0))
114 self.assertEqual((1.0, 0.4, 0.0), grapefruit.Color.RgbToWebSafe(1, 0.55, 0.0, True))
115 self.assertEqual((1.0, 0.4, 0.0), grapefruit.Color.RgbToWebSafe(1, 0.5, 0.0, True))
116
117 def testRgbToGreyscale(self):
118 self.assertEqual((0.6, 0.6, 0.6), grapefruit.Color.RgbToGreyscale(1, 0.8, 0))
119
120 class NewFromTest(GrapeFruitTestCase):
121 '''Test the static color instanciation methods.'''
122 def testNewFromRgb(self):
123 c = grapefruit.Color.NewFromRgb(1.0, 0.5, 0.0)
124 self.assertEqual(c, (1.0, 0.5, 0.0, 1.0))
125 c = grapefruit.Color.NewFromRgb(1.0, 0.5, 0.0, 0.5)
126 self.assertEqual(c, (1.0, 0.5, 0.0, 0.5))
127
128 def testNewFromHsl(self):
129 c = grapefruit.Color.NewFromHsl(30, 1, 0.5)
130 self.assertEqual(c, (1.0, 0.5, 0.0, 1.0))
131 c = grapefruit.Color.NewFromHsl(30, 1, 0.5, 0.5)
132 self.assertEqual(c, (1.0, 0.5, 0.0, 0.5))
133
134 def testNewFromHsv(self):
135 c = grapefruit.Color.NewFromHsv(30, 1, 1)
136 self.assertEqual(c, (1.0, 0.5, 0.0, 1.0))
137 c = grapefruit.Color.NewFromHsv(30, 1, 1, 0.5)
138 self.assertEqual(c, (1.0, 0.5, 0.0, 0.5))
139
140 def testNewFromYiq(self):
141 c = grapefruit.Color.NewFromYiq(0.5923, 0.4589, -0.0499818)
142 self.assertNear(c, (1, 0.5, 0, 1))
143 c = grapefruit.Color.NewFromYiq(0.5923, 0.4589,-0.05, 0.5)
144 self.assertNear(c, (1, 0.5, 0, 0.5))
145
146 def testNewFromYuv(self):
147 c = grapefruit.Color.NewFromYuv(0.5925, -0.2916, 0.3575)
148 self.assertNear(c, (1, 0.5, 0, 1))
149 c = grapefruit.Color.NewFromYuv(0.5925, -0.2916, 0.3575, 0.5)
150 self.assertNear(c, (1, 0.5, 0, 0.5))
151
152 def testNewFromXyz(self):
153 c = grapefruit.Color.NewFromXyz(0.488941, 0.365682, 0.0448137)
154 self.assertNear(c, (1, 0.5, 0, 1))
155 c = grapefruit.Color.NewFromXyz(0.488941, 0.365682, 0.0448137, 0.5)
156 self.assertNear(c, (1, 0.5, 0, 0.5))
157
158 def testNewFromLab(self):
159 c = grapefruit.Color.NewFromLab(66.9518, 0.43084, 0.739692)
160 self.assertNear(c, (1, 0.5, 0, 1))
161 c = grapefruit.Color.NewFromLab(66.9518, 0.43084, 0.739692, wref=grapefruit.Color.WHITE_REFERENCE["std_D50"])
162 self.assertNear(c, (1.0123754, 0.492012, -0.143110, 1))
163 c = grapefruit.Color.NewFromLab(66.9518, 0.43084, 0.739692, 0.5)
164 self.assertNear(c, (1, 0.5, 0, 0.5))
165 c = grapefruit.Color.NewFromLab(66.9518, 0.43084, 0.739692, 0.5, grapefruit.Color.WHITE_REFERENCE["std_D50"])
166 self.assertNear(c, (1.0123754, 0.492012, -0.143110, 0.5))
167
168 def testNewFromLabInteger(self):
169 # Allow specifying lightness as an integer.
170 lab = (60, 0.3, 0.3)
171 c = grapefruit.Color.NewFromLab(*lab)
172 self.assertNear(c.lab, lab)
173 self.assertTrue(c.isLegal)
174
175 def testNewFromCmy(self):
176 c = grapefruit.Color.NewFromCmy(0, 0.5, 1)
177 self.assertEqual(c, (1, 0.5, 0, 1.0))
178 c = grapefruit.Color.NewFromCmy(0, 0.5, 1, 0.5)
179 self.assertEqual(c, (1, 0.5, 0, 0.5))
180
181 def testNewFromCmyk(self):
182 c = grapefruit.Color.NewFromCmyk(1, 0.32, 0, 0.5)
183 self.assertNear(c, (0, 0.34, 0.5, 1))
184 c = grapefruit.Color.NewFromCmyk(1, 0.32, 0, 0.5, 0.5)
185 self.assertNear(c, (0, 0.34, 0.5, 0.5))
186
187 def testNewFromHtml(self):
188 c = grapefruit.Color.NewFromHtml("#ff8000")
189 self.assertNear(c, (1, 0.5020, 0, 1))
190 c = grapefruit.Color.NewFromHtml("ff8000")
191 self.assertNear(c, (1, 0.5020, 0, 1))
192 c = grapefruit.Color.NewFromHtml("#f60")
193 self.assertNear(c, (1, 0.4, 0, 1))
194 c = grapefruit.Color.NewFromHtml("f60")
195 self.assertNear(c, (1, 0.4, 0, 1))
196 c = grapefruit.Color.NewFromHtml("lemonchiffon")
197 self.assertNear(c, (1, 0.9804, 0.8039, 1))
198 c = grapefruit.Color.NewFromHtml("#ff8000", 0.5)
199 self.assertNear(c, (1, 0.5020, 0, 0.5))
200
201 def testNewFromPil(self):
202 c = grapefruit.Color.NewFromPil(0x0080ff)
203 self.assertNear(c, (1, 0.5020, 0, 1))
204 c = grapefruit.Color.NewFromPil(0x0080ff, 0.5)
205 self.assertNear(c, (1, 0.5020, 0, 0.5))
206
207
208 class ColorTest(GrapeFruitTestCase):
209 def setUp(self):
210 self.rgbCol = grapefruit.Color.NewFromRgb(1.0, 0.5, 0.0)
211 self.hslCol = grapefruit.Color.NewFromHsl(30, 1, 0.5)
212 self.hslCol2 = grapefruit.Color.NewFromHsl(30, 0.5, 0.5)
213
214 def testInit(self):
215 self.assertEqual(grapefruit.Color((1.0, 0.5, 0.0)), (1.0, 0.5, 0.0, 1.0))
216 self.assertEqual(grapefruit.Color((1.0, 0.5, 0.0), mode='rgb'), (1.0, 0.5, 0.0, 1.0))
217 self.assertEqual(grapefruit.Color((30, 1, 0.5), mode='hsl'), (1.0, 0.5, 0.0, 1.0))
218
219 self.assertRaises(ValueError, grapefruit.Color, (30, 1, 0.5), 'hsv')
220
221 def testEq(self):
222 self.assertEqual(self.rgbCol, self.hslCol)
223 self.assertEqual(self.rgbCol, (1.0, 0.5, 0.0, 1.0))
224 self.assertEqual(self.rgbCol, [1.0, 0.5, 0.0, 1.0])
225 self.assertEqual([1.0, 0.5, 0.0, 1.0], self.rgbCol)
226 self.assertNotEqual(self.rgbCol, '(1.0, 0.5, 0.0, 1.0)')
227
228 def testRepr(self):
229 self.assertEqual(repr(self.rgbCol), '(1.0, 0.5, 0.0, 1.0)')
230 self.assertEqual(repr(self.hslCol), '(1.0, 0.5, 0.0, 1.0)')
231
232 def testStr(self):
233 self.assertEqual(str(self.rgbCol), '(1, 0.5, 0, 1)')
234 self.assertEqual(str(self.hslCol), '(1, 0.5, 0, 1)')
235
236 def testIter(self):
237 self.assertEqual([1, 0.5, 0, 1], list(iter(self.rgbCol)))
238
239 def testProperties(self):
240 self.assertEqual(self.rgbCol.alpha, 1.0)
241 self.assertEqual(self.rgbCol.whiteRef, grapefruit.Color.WHITE_REFERENCE['std_D65'])
242 self.assertEqual(self.rgbCol.rgb, (1, 0.5, 0))
243 self.assertEqual(self.hslCol.hue, 30)
244 self.assertEqual(self.rgbCol.hsl, (30, 1, 0.5))
245 self.assertEqual(self.rgbCol.hsv, (30, 1, 1))
246 self.assertNear(self.rgbCol.yiq, (0.5923, 0.4589, -0.05))
247 self.assertNear(self.rgbCol.yuv, (0.5925, -0.2916, 0.3575))
248 self.assertNear(self.rgbCol.xyz, (0.4890, 0.3657, 0.04485))
249 self.assertNear(self.rgbCol.lab, (66.9518, 0.4308, 0.7397))
250 self.assertEqual(self.rgbCol.cmy, (0, 0.5, 1))
251 self.assertEqual(self.rgbCol.cmyk, (0, 0.5, 1, 0))
252 self.assertEqual(self.rgbCol.intTuple, (255, 128, 0))
253 self.assertEqual(self.rgbCol.html, '#ff8000')
254 self.assertEqual(self.rgbCol.pil, 0x0080ff)
255 self.assertEqual(self.rgbCol.webSafe, (1, 0.6, 0))
256 self.assertEqual(self.rgbCol.greyscale, (0.5, 0.5, 0.5))
257
258 c = grapefruit.Color.NewFromRgb(1, 0.5, 0, wref=grapefruit.Color.WHITE_REFERENCE['std_D50'])
259 self.assertNear(c.lab, (66.9518, 0.4117, 0.6728))
260
261 def testColorWitgAlpha(self):
262 self.assertEqual(self.rgbCol.ColorWithAlpha(0.5), (1, 0.5, 0, 0.5))
263
264 def testColorWithWhiteRef(self):
265 self.assertEqual(self.hslCol.ColorWithWhiteRef((0.1, 0.2, 0.3)).whiteRef, (0.1, 0.2, 0.3))
266
267 def testColorWithHue(self):
268 self.assertEqual(self.hslCol.ColorWithHue(60), (1.0, 1.0, 0.0, 1.0))
269 self.assertEqual(self.hslCol.ColorWithHue(60).hsl, (60, 1, 0.5))
270
271 def testColorWithSaturation(self):
272 self.assertEqual(self.hslCol.ColorWithSaturation(0.5), (0.75, 0.5, 0.25, 1.0))
273 self.assertEqual(self.hslCol.ColorWithSaturation(0.5).hsl, (30, 0.5, 0.5))
274
275 def testColorWithLightness(self):
276 self.assertEqual(self.hslCol.ColorWithLightness(1), (1.0, 1.0, 1.0, 1.0))
277 self.assertEqual(self.hslCol.ColorWithLightness(1).hsl, (30, 1.0, 1.0))
278
279 def testDarkerColor(self):
280 self.assertNear(self.hslCol.DarkerColor(0.2), (0.6, 0.3, 0.0, 1.0))
281 self.assertNear(self.hslCol.DarkerColor(0.2).hsl, (30, 1, 0.3))
282
283 def testLighterColor(self):
284 self.assertNear(self.hslCol.LighterColor(0.2), (1.0, 0.7, 0.4, 1.0))
285 self.assertNear(self.hslCol.LighterColor(0.2).hsl, (30, 1, 0.7))
286
287 def testSaturate(self):
288 self.assertNear(self.hslCol2.Saturate(0.25), (0.875, 0.5, 0.125, 1.0))
289 self.assertNear(self.hslCol2.Saturate(0.25).hsl, (30, 0.75, 0.5))
290
291 def testDesaturate(self):
292 self.assertNear(self.hslCol2.Desaturate(0.25), (0.625, 0.5, 0.375, 1.0))
293 self.assertNear(self.hslCol2.Desaturate(0.25).hsl, (30, 0.25, 0.5))
294
295 def testWebSafeDither(self):
296 dithered = (
297 (1.0, 0.6, 0.0, 1.0),
298 (1.0, 0.4, 0.0, 1.0))
299 self.assertEqual(self.rgbCol.WebSafeDither(), dithered)
300
301 def testGradient(self):
302 gradient = [
303 (0.75, 0.25, 0.0, 1.0),
304 (0.5, 0.5, 0.0, 1.0),
305 (0.25, 0.75, 0.0, 1.0)]
306 c1 = grapefruit.Color.NewFromRgb(1.0, 0.0, 0.0)
307 c2 = grapefruit.Color.NewFromRgb(0.0, 1.0, 0.0)
308 self.assertEqual(gradient, c1.Gradient(c2, 3))
309
310 def testComplementaryColor(self):
311 self.assertEqual(self.hslCol.ComplementaryColor(mode='rgb').hsl, (210, 1, 0.5))
312
313 def testMonochromeScheme(self):
314 monochrome = (
315 (0.94, 0.8, 0.66, 1.0), # hsl(30, 0.7, 0.8)
316 (0.6, 0.3, 0.0, 1.0), # hsl(30, 1, 0.3)
317 (0.88, 0.6, 0.32, 1.0), # hsl(30, 0.7, 0.6)
318 (1.0, 0.8, 0.6, 1.0)) # hsl(30, 1, 0.8)
319 scheme = self.rgbCol.MonochromeScheme()
320 for i in range(len(monochrome)):
321 self.assertNear(scheme[i], monochrome[i])
322
323 def testTriadicScheme(self):
324 triad = (
325 (0.0, 1.0, 0.5, 1.0),
326 (0.5, 0.0, 1.0, 1.0))
327 self.assertEqual(self.rgbCol.TriadicScheme(mode='rgb'), triad)
328
329 def testTetradicScheme(self):
330 tetrad = (
331 (0.5, 1.0, 0.0, 1.0),
332 (0.0, 0.5, 1.0, 1.0),
333 (0.5, 0.0, 1.0, 1.0))
334 self.assertEqual(self.rgbCol.TetradicScheme(mode='rgb'), tetrad)
335
336 def testAnalogousScheme(self):
337 scheme = (
338 (1.0, 0.0, 0.0, 1.0),
339 (1.0, 1.0, 0.0, 1.0))
340 self.assertEqual(self.rgbCol.AnalogousScheme(mode='rgb'), scheme)
341
342 def testAlphaBlend(self):
343 c1 = grapefruit.Color.NewFromRgb(1, 0.5, 0, alpha = 0.2)
344 c2 = grapefruit.Color.NewFromRgb(1, 1, 1, alpha = 0.8)
345 self.assertNear(c1.AlphaBlend(c2), (1, 0.875, 0.75, 0.84))
346
347 def testBlend(self):
348 c1 = grapefruit.Color.NewFromRgb(1, 0.5, 0, alpha = 0.2)
349 c2 = grapefruit.Color.NewFromRgb(1, 1, 1, alpha = 0.6)
350 self.assertEqual(c1.Blend(c2), (1, 0.75, 0.5, 0.4))
351
352 def testNearestLegal(self):
353 c = grapefruit.Color.NewFromRgb(1.1, -0.1, 0.5, alpha=1.1)
354 self.assertFalse(c.isLegal)
355 self.assertNear(c.nearestLegal.rgb, (1.0, 0.0, 0.5))
356 self.assertNear(c.nearestLegal.alpha, 1.0)
357
358 def suite():
359 return unittest.TestLoader().loadTestsFromName(__name__)
360
361 if __name__ == '__main__':
362 unittest.main(defaultTest='suite')
363 pass
364
365 # vim: ts=2 sts=2 sw=2 et
+0
-5
setup.cfg less more
0 [egg_info]
1 tag_build =
2 tag_date = 0
3 tag_svn_revision = 0
4
1616
1717 '''GrapeFruit setup and build script.'''
1818
19 # $Id: setup.py 24 2008-05-25 16:23:22Z xbasty $
19 # $Id$
2020 __author__ = 'Xavier Basty <xbasty@gmail.com>'
21 __version__ = '0.1a3'
21 __version__ = '0.1a4'
2222
2323
2424 # The base package metadata to be used by both distutils and setuptools
5555 return open(file).read()
5656
5757 def BuildLongDescription():
58 return '\n'.join([Read('README'), Read('CHANGES')])
58 return '\n'.join([Read('README.rst'), Read('CHANGES')])
5959
6060 def Main():
6161 # Build the long_description from the README and CHANGES files