Codebase list grapefruit / 418760c
Imported Upstream version 0.1~a3+dfsg SVN-Git Migration 8 years ago
20 changed file(s) with 3771 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 2008-06-15
1 - Released 0.1a3
2 - Added Gradient
3
4 2008-06-01
5 - Fixed overflow in alpha blending.
6
7 2008-05-29
8 - Added Saturate/Desaturate.
9 - Added MonochromeScheme
10 - Added the mode parameter to the generation methods to choose the
11 color wheel use for the generation (ryb/rgb).
12
13 2008-05-28
14 - Added the RGB<->RYB hue conversion.
15 - Added an angle parameter to the tetrad scheme to control the shape of
16 the rectangle.
17
18 2008-05-27
19 - Released 0.1a2
20
21 2008-05-24
22
23 - Fixed the HSL->RGB conversion
24 (the modulo in the hue conversion was 60 instead of 6.0!)
25 Updated the unit tests (which were wrong!)
26
27 2008-05-24
28
29 Released 0.1a1
30 - Convert the documentation to Sphinx
31 - Completed the unit tests
32 - Fixed some stupid typos
33
34 2008-05-22
35
36 - Refactored pretty much everything to more standard "Python coding style".
37 - Replaced the global variables by Color properties.
38 - Moved the module functions to static methods of Color.
39 - Completed the CIE white point dictionary to include all the standard
40 illuminants.
41 - Added doctest for all the functions.
42 - Fixed the conversions factors to get better results (more exact and
43 more symmetric).
44 - Changed the range of the L component from [0~1] to [0~100] (as it should
45 have been).
46 - Added packaging data and setup.
47 - Changed the structure of the unit tests.
48
49 2008-05-08
50
51 Released 0.1a0
52 - Initial checkin of grapefruit
0 Copyright (c) 2008, Xavier Basty
1
2 Licensed under the Apache License, Version 2.0 (the "License");
3 you may not use this file except in compliance with the License.
4 You may obtain a copy of the License at
5
6 http://www.apache.org/licenses/LICENSE-2.0
7
8 Unless required by applicable law or agreed to in writing, software
9 distributed under the License is distributed on an "AS IS" BASIS,
10 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 See the License for the specific language governing permissions and
12 limitations under the License.
0 Apache License
1 Version 2.0, January 2004
2 http://www.apache.org/licenses/
3
4 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
5
6 1. Definitions.
7
8 "License" shall mean the terms and conditions for use, reproduction,
9 and distribution as defined by Sections 1 through 9 of this document.
10
11 "Licensor" shall mean the copyright owner or entity authorized by
12 the copyright owner that is granting the License.
13
14 "Legal Entity" shall mean the union of the acting entity and all
15 other entities that control, are controlled by, or are under common
16 control with that entity. For the purposes of this definition,
17 "control" means (i) the power, direct or indirect, to cause the
18 direction or management of such entity, whether by contract or
19 otherwise, or (ii) ownership of fifty percent (50%) or more of the
20 outstanding shares, or (iii) beneficial ownership of such entity.
21
22 "You" (or "Your") shall mean an individual or Legal Entity
23 exercising permissions granted by this License.
24
25 "Source" form shall mean the preferred form for making modifications,
26 including but not limited to software source code, documentation
27 source, and configuration files.
28
29 "Object" form shall mean any form resulting from mechanical
30 transformation or translation of a Source form, including but
31 not limited to compiled object code, generated documentation,
32 and conversions to other media types.
33
34 "Work" shall mean the work of authorship, whether in Source or
35 Object form, made available under the License, as indicated by a
36 copyright notice that is included in or attached to the work
37 (an example is provided in the Appendix below).
38
39 "Derivative Works" shall mean any work, whether in Source or Object
40 form, that is based on (or derived from) the Work and for which the
41 editorial revisions, annotations, elaborations, or other modifications
42 represent, as a whole, an original work of authorship. For the purposes
43 of this License, Derivative Works shall not include works that remain
44 separable from, or merely link (or bind by name) to the interfaces of,
45 the Work and Derivative Works thereof.
46
47 "Contribution" shall mean any work of authorship, including
48 the original version of the Work and any modifications or additions
49 to that Work or Derivative Works thereof, that is intentionally
50 submitted to Licensor for inclusion in the Work by the copyright owner
51 or by an individual or Legal Entity authorized to submit on behalf of
52 the copyright owner. For the purposes of this definition, "submitted"
53 means any form of electronic, verbal, or written communication sent
54 to the Licensor or its representatives, including but not limited to
55 communication on electronic mailing lists, source code control systems,
56 and issue tracking systems that are managed by, or on behalf of, the
57 Licensor for the purpose of discussing and improving the Work, but
58 excluding communication that is conspicuously marked or otherwise
59 designated in writing by the copyright owner as "Not a Contribution."
60
61 "Contributor" shall mean Licensor and any individual or Legal Entity
62 on behalf of whom a Contribution has been received by Licensor and
63 subsequently incorporated within the Work.
64
65 2. Grant of Copyright License. Subject to the terms and conditions of
66 this License, each Contributor hereby grants to You a perpetual,
67 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
68 copyright license to reproduce, prepare Derivative Works of,
69 publicly display, publicly perform, sublicense, and distribute the
70 Work and such Derivative Works in Source or Object form.
71
72 3. Grant of Patent License. Subject to the terms and conditions of
73 this License, each Contributor hereby grants to You a perpetual,
74 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
75 (except as stated in this section) patent license to make, have made,
76 use, offer to sell, sell, import, and otherwise transfer the Work,
77 where such license applies only to those patent claims licensable
78 by such Contributor that are necessarily infringed by their
79 Contribution(s) alone or by combination of their Contribution(s)
80 with the Work to which such Contribution(s) was submitted. If You
81 institute patent litigation against any entity (including a
82 cross-claim or counterclaim in a lawsuit) alleging that the Work
83 or a Contribution incorporated within the Work constitutes direct
84 or contributory patent infringement, then any patent licenses
85 granted to You under this License for that Work shall terminate
86 as of the date such litigation is filed.
87
88 4. Redistribution. You may reproduce and distribute copies of the
89 Work or Derivative Works thereof in any medium, with or without
90 modifications, and in Source or Object form, provided that You
91 meet the following conditions:
92
93 (a) You must give any other recipients of the Work or
94 Derivative Works a copy of this License; and
95
96 (b) You must cause any modified files to carry prominent notices
97 stating that You changed the files; and
98
99 (c) You must retain, in the Source form of any Derivative Works
100 that You distribute, all copyright, patent, trademark, and
101 attribution notices from the Source form of the Work,
102 excluding those notices that do not pertain to any part of
103 the Derivative Works; and
104
105 (d) If the Work includes a "NOTICE" text file as part of its
106 distribution, then any Derivative Works that You distribute must
107 include a readable copy of the attribution notices contained
108 within such NOTICE file, excluding those notices that do not
109 pertain to any part of the Derivative Works, in at least one
110 of the following places: within a NOTICE text file distributed
111 as part of the Derivative Works; within the Source form or
112 documentation, if provided along with the Derivative Works; or,
113 within a display generated by the Derivative Works, if and
114 wherever such third-party notices normally appear. The contents
115 of the NOTICE file are for informational purposes only and
116 do not modify the License. You may add Your own attribution
117 notices within Derivative Works that You distribute, alongside
118 or as an addendum to the NOTICE text from the Work, provided
119 that such additional attribution notices cannot be construed
120 as modifying the License.
121
122 You may add Your own copyright statement to Your modifications and
123 may provide additional or different license terms and conditions
124 for use, reproduction, or distribution of Your modifications, or
125 for any such Derivative Works as a whole, provided Your use,
126 reproduction, and distribution of the Work otherwise complies with
127 the conditions stated in this License.
128
129 5. Submission of Contributions. Unless You explicitly state otherwise,
130 any Contribution intentionally submitted for inclusion in the Work
131 by You to the Licensor shall be under the terms and conditions of
132 this License, without any additional terms or conditions.
133 Notwithstanding the above, nothing herein shall supersede or modify
134 the terms of any separate license agreement you may have executed
135 with Licensor regarding such Contributions.
136
137 6. Trademarks. This License does not grant permission to use the trade
138 names, trademarks, service marks, or product names of the Licensor,
139 except as required for reasonable and customary use in describing the
140 origin of the Work and reproducing the content of the NOTICE file.
141
142 7. Disclaimer of Warranty. Unless required by applicable law or
143 agreed to in writing, Licensor provides the Work (and each
144 Contributor provides its Contributions) on an "AS IS" BASIS,
145 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
146 implied, including, without limitation, any warranties or conditions
147 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
148 PARTICULAR PURPOSE. You are solely responsible for determining the
149 appropriateness of using or redistributing the Work and assume any
150 risks associated with Your exercise of permissions under this License.
151
152 8. Limitation of Liability. In no event and under no legal theory,
153 whether in tort (including negligence), contract, or otherwise,
154 unless required by applicable law (such as deliberate and grossly
155 negligent acts) or agreed to in writing, shall any Contributor be
156 liable to You for damages, including any direct, indirect, special,
157 incidental, or consequential damages of any character arising as a
158 result of this License or out of the use or inability to use the
159 Work (including but not limited to damages for loss of goodwill,
160 work stoppage, computer failure or malfunction, or any and all
161 other commercial damages or losses), even if such Contributor
162 has been advised of the possibility of such damages.
163
164 9. Accepting Warranty or Additional Liability. While redistributing
165 the Work or Derivative Works thereof, You may choose to offer,
166 and charge a fee for, acceptance of support, warranty, indemnity,
167 or other liability obligations and/or rights consistent with this
168 License. However, in accepting such obligations, You may act only
169 on Your own behalf and on Your sole responsibility, not on behalf
170 of any other Contributor, and only if You agree to indemnify,
171 defend, and hold each Contributor harmless for any liability
172 incurred by, or claims asserted against, such Contributor by reason
173 of your accepting any such warranty or additional liability.
174
175 END OF TERMS AND CONDITIONS
176
177 APPENDIX: How to apply the Apache License to your work.
178
179 To apply the Apache License to your work, attach the following
180 boilerplate notice, with the fields enclosed by brackets "[]"
181 replaced with your own identifying information. (Don't include
182 the brackets!) The text should be enclosed in the appropriate
183 comment syntax for the file format. We also recommend that a
184 file or class name and description of purpose be included on the
185 same "printed page" as the copyright notice for easier
186 identification within third-party archives.
187
188 Copyright [yyyy] [name of copyright owner]
189
190 Licensed under the Apache License, Version 2.0 (the "License");
191 you may not use this file except in compliance with the License.
192 You may obtain a copy of the License at
193
194 http://www.apache.org/licenses/LICENSE-2.0
195
196 Unless required by applicable law or agreed to in writing, software
197 distributed under the License is distributed on an "AS IS" BASIS,
198 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
199 See the License for the specific language governing permissions and
200 limitations under the License.
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 =====================
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 GrapeFruit's TODO list
1 ----------------------
2
3 Patches and bug reports are welcome, just please keep the style consistent
4 with the original source.
5
6 * grapefruit_test isn't much more that a copy of the doctests right now.
7 Complete it with real unit tests that better define the module behavior.
8
9 * Add sRGB <-> AdobeRGB conversion.
0 # Makefile for Sphinx documentation
1 #
2
3 # You can set these variables from the command line.
4 SPHINXOPTS =
5 SPHINXBUILD = sphinx-build
6 PAPER =
7
8 # Internal variables.
9 PAPEROPT_a4 = -D latex_paper_size=a4
10 PAPEROPT_letter = -D latex_paper_size=letter
11 ALLSPHINXOPTS = -d _build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
12
13 .PHONY: help clean html web pickle htmlhelp latex changes linkcheck
14
15 help:
16 @echo "Please use \`make <target>' where <target> is one of"
17 @echo " html to make standalone HTML files"
18 @echo " pickle to make pickle files (usable by e.g. sphinx-web)"
19 @echo " htmlhelp to make HTML files and a HTML help project"
20 @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
21 @echo " changes to make an overview over all changed/added/deprecated items"
22 @echo " linkcheck to check all external links for integrity"
23
24 clean:
25 -rm -rf _build/*
26
27 html:
28 mkdir -p _build/html _build/doctrees
29 $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) _build/html
30 @echo
31 @echo "Build finished. The HTML pages are in _build/html."
32
33 pickle:
34 mkdir -p _build/pickle _build/doctrees
35 $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) _build/pickle
36 @echo
37 @echo "Build finished; now you can process the pickle files or run"
38 @echo " sphinx-web _build/pickle"
39 @echo "to start the sphinx-web server."
40
41 web: pickle
42
43 htmlhelp:
44 mkdir -p _build/htmlhelp _build/doctrees
45 $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) _build/htmlhelp
46 @echo
47 @echo "Build finished; now you can run HTML Help Workshop with the" \
48 ".hhp project file in _build/htmlhelp."
49
50 latex:
51 mkdir -p _build/latex _build/doctrees
52 $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) _build/latex
53 @echo
54 @echo "Build finished; the LaTeX files are in _build/latex."
55 @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
56 "run these through (pdf)latex."
57
58 changes:
59 mkdir -p _build/changes _build/doctrees
60 $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) _build/changes
61 @echo
62 @echo "The overview file is in _build/changes."
63
64 linkcheck:
65 mkdir -p _build/linkcheck _build/doctrees
66 $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) _build/linkcheck
67 @echo
68 @echo "Link check complete; look for any errors in the above output " \
69 "or in _build/linkcheck/output.txt."
0 # -*- coding: utf-8 -*-
1 #
2 # GrapeFruit documentation build configuration file, created by
3 # sphinx-quickstart on Sat May 24 00:09:48 2008.
4 #
5 # This file is execfile()d with the current directory set to its containing dir.
6 #
7 # The contents of this file are pickled, so don't put values in the namespace
8 # that aren't pickleable (module imports are okay, they're removed automatically).
9 #
10 # All configuration values have a default value; values that are commented out
11 # serve to show the default value.
12 #
13 # $Id: conf.py 14 2008-05-24 09:46:30Z xbasty $
14
15 import sys, os
16
17 # If your extensions are in another directory, add it here. If the directory
18 # is relative to the documentation root, use os.path.abspath to make it
19 # absolute, like shown here.
20 #sys.path.append(os.path.abspath('some/directory'))
21
22 # General configuration
23 # ---------------------
24
25 # Add any Sphinx extension module names here, as strings. They can be extensions
26 # coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
27 extensions = ['sphinx.ext.autodoc']
28
29 # Add any paths that contain templates here, relative to this directory.
30 templates_path = ['_templates']
31
32 # The suffix of source filenames.
33 source_suffix = '.rst'
34
35 # The master toctree document.
36 master_doc = 'index'
37
38 # General substitutions.
39 project = 'GrapeFruit'
40 copyright = '2008, Xavier Basty <xbasty@gmail.com>'
41
42 # The default replacements for |version| and |release|, also used in various
43 # other places throughout the built documents.
44 #
45 # The short X.Y version.
46 version = '0.1'
47 # The full version, including alpha/beta/rc tags.
48 release = '0.1a3'
49
50 # There are two options for replacing |today|: either, you set today to some
51 # non-false value, then it is used:
52 #today = ''
53 # Else, today_fmt is used as the format for a strftime call.
54 today_fmt = '%B %d, %Y'
55
56 # List of documents that shouldn't be included in the build.
57 #unused_docs = []
58
59 # List of directories, relative to source directories, that shouldn't be searched
60 # for source files.
61 #exclude_dirs = []
62
63 # If true, '()' will be appended to :func: etc. cross-reference text.
64 #add_function_parentheses = True
65
66 # If true, the current module name will be prepended to all description
67 # unit titles (such as .. function::).
68 #add_module_names = True
69
70 # If true, sectionauthor and moduleauthor directives will be shown in the
71 # output. They are ignored by default.
72 #show_authors = False
73
74 # The name of the Pygments (syntax highlighting) style to use.
75 pygments_style = 'sphinx'
76
77
78 # Options for HTML output
79 # -----------------------
80
81 # The style sheet to use for HTML and HTML Help pages. A file of that name
82 # must exist either in Sphinx' static/ path, or in one of the custom paths
83 # given in html_static_path.
84 html_style = 'default.css'
85
86 # The name for this set of Sphinx documents. If None, it defaults to
87 # "<project> v<release> documentation".
88 #html_title = None
89
90 # The name of an image file (within the static path) to place at the top of
91 # the sidebar.
92 #html_logo = None
93
94 # Add any paths that contain custom static files (such as style sheets) here,
95 # relative to this directory. They are copied after the builtin static files,
96 # so a file named "default.css" will overwrite the builtin "default.css".
97 html_static_path = ['_static']
98
99 # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
100 # using the given strftime format.
101 html_last_updated_fmt = '%b %d, %Y'
102
103 # If true, SmartyPants will be used to convert quotes and dashes to
104 # typographically correct entities.
105 #html_use_smartypants = True
106
107 # Custom sidebar templates, maps document names to template names.
108 #html_sidebars = {}
109
110 # Additional templates that should be rendered to pages, maps page names to
111 # template names.
112 #html_additional_pages = {}
113
114 # If false, no module index is generated.
115 #html_use_modindex = True
116
117 # If true, the reST sources are included in the HTML build as _sources/<name>.
118 #html_copy_source = True
119
120 # If true, an OpenSearch description file will be output, and all pages will
121 # contain a <link> tag referring to it. The value of this option must be the
122 # base URL from which the finished HTML is served.
123 #html_use_opensearch = ''
124
125 # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
126 #html_file_suffix = ''
127
128 # Output file base name for HTML help builder.
129 htmlhelp_basename = 'GrapeFruitdoc'
130
131
132 # Options for LaTeX output
133 # ------------------------
134
135 # The paper size ('letter' or 'a4').
136 #latex_paper_size = 'letter'
137
138 # The font size ('10pt', '11pt' or '12pt').
139 #latex_font_size = '10pt'
140
141 # Grouping the document tree into LaTeX files. List of tuples
142 # (source start file, target name, title, author, document class [howto/manual]).
143 latex_documents = [
144 ('index', 'GrapeFruit.tex', 'GrapeFruit Documentation', 'Xavier Basty <xbasty@gmail.com>', 'manual'),
145 ]
146
147 # The name of an image file (relative to this directory) to place at the top of
148 # the title page.
149 #latex_logo = None
150
151 # For "manual" documents, if this is true, then toplevel headings are parts,
152 # not chapters.
153 #latex_use_parts = False
154
155 # Additional stuff for the LaTeX preamble.
156 #latex_preamble = ''
157
158 # Documents to append as an appendix to all manuals.
159 #latex_appendices = []
160
161 # If false, no module index is generated.
162 #latex_use_modindex = True
0 .. _grapefruit-index:
1
2 .. image:: _static/GrapeFruit.png
3
4 Welcome! This is the documentation for GrapeFruit |release|,
5 last updated |today|.
6
7 See the :ref:`genindex` for a list of the topics.
8
9
10 .. module:: grapefruit
11 .. moduleauthor:: Xavier Basty <xbasty@gmail.com>
12
13 ==========================
14 The Color class
15 ==========================
16
17 .. class:: Color
18
19 The grapefruit module contains only the :class:`Color` class, which exposes all
20 the functionnalities. It can be used to store a color value and manipulate it,
21 or convert it to another color system.
22
23 If you are only interested in converting you colors from one system to another,
24 you can store them using regular tuples instead of :class:`Color` instances.
25 You can then use the class static methods to perform the conversions.
26
27 :class:`Color` stores both the RGB and HSL representation of the color.
28 This makes possible to keep the hue intact when the color is a pure white
29 due to its lightness.
30 However, certain operations work only with the RGB values, and might then
31 lose the hue.
32
33 All the operations assume that you provide values in the specified ranges,
34 no checks are made whatsoever. If you provide a value outside of the
35 specified ranges, you'll get some strange results...
36
37 The class instances are immutable, all the methods return a new instance
38 of the :class:`Color` class, and all the properties are read-only.
39
40 .. note::
41
42 Some operations may provide results a bit outside the specified ranges,
43 the results are not capped.
44 This is due to certain color systems having a widers gamut than others.
45
46
47 Class content
48 ---------------
49
50 - :ref:`class-constants`
51
52 - :const:`Color.WHITE_REFERENCE`
53 - :const:`Color.NAMED_COLOR`
54
55 - :ref:`conversion-functions`
56
57 - :meth:`Color.RgbToHsl`
58 - :meth:`Color.HslToRgb`
59 - :meth:`Color.RgbToHsv`
60 - :meth:`Color.HsvToRgb`
61 - :meth:`Color.RgbToYiq`
62 - :meth:`Color.YiqToRgb`
63 - :meth:`Color.RgbToYuv`
64 - :meth:`Color.YuvToRgb`
65 - :meth:`Color.RgbToXyz`
66 - :meth:`Color.XyzToRgb`
67 - :meth:`Color.XyzToLab`
68 - :meth:`Color.LabToXyz`
69 - :meth:`Color.CmykToCmy`
70 - :meth:`Color.CmyToCmyk`
71 - :meth:`Color.RgbToCmy`
72 - :meth:`Color.CmyToRgb`
73 - :meth:`Color.RgbToHtml`
74 - :meth:`Color.HtmlToRgb`
75 - :meth:`Color.RgbToPil`
76 - :meth:`Color.PilToRgb`
77 - :meth:`Color.RgbToWebSafe`
78 - :meth:`Color.RgbToGreyscale`
79 - :meth:`Color.RgbToRyb`
80 - :meth:`Color.RybToRgb`
81
82 - :ref:`instantiation-functions`
83
84 - :meth:`Color.NewFromRgb`
85 - :meth:`Color.NewFromHsl`
86 - :meth:`Color.NewFromHsv`
87 - :meth:`Color.NewFromYiq`
88 - :meth:`Color.NewFromYuv`
89 - :meth:`Color.NewFromXyz`
90 - :meth:`Color.NewFromLab`
91 - :meth:`Color.NewFromCmy`
92 - :meth:`Color.NewFromCmyk`
93 - :meth:`Color.NewFromHtml`
94 - :meth:`Color.NewFromPil`
95
96 - :ref:`properties`
97
98 - :attr:`Color.alpha`
99 - :attr:`Color.whiteRef`
100 - :attr:`Color.rgb`
101 - :attr:`Color.hue`
102 - :attr:`Color.hsl`
103 - :attr:`Color.hsv`
104 - :attr:`Color.yiq`
105 - :attr:`Color.yuv`
106 - :attr:`Color.xyz`
107 - :attr:`Color.lab`
108 - :attr:`Color.cmy`
109 - :attr:`Color.cmyk`
110 - :attr:`Color.html`
111 - :attr:`Color.pil`
112 - :attr:`Color.webSafe`
113 - :attr:`Color.greyscale`
114
115 - :ref:`manipulation-methods`
116
117 - :meth:`Color.ColorWithAlpha`
118 - :meth:`Color.ColorWithWhiteRef`
119 - :meth:`Color.ColorWithHue`
120 - :meth:`Color.ColorWithSaturation`
121 - :meth:`Color.ColorWithLightness`
122 - :meth:`Color.DarkerColor`
123 - :meth:`Color.LighterColor`
124 - :meth:`Color.Saturate`
125 - :meth:`Color.Desaturate`
126 - :meth:`Color.WebSafeDither`
127
128 - :ref:`generation-methods`
129
130 - :meth:`Color.Gradient`
131 - :meth:`Color.ComplementaryColor`
132 - :meth:`Color.TriadicScheme`
133 - :meth:`Color.TetradicScheme`
134 - :meth:`Color.AnalogousScheme`
135
136 - :ref:`blending-methods`
137
138 - :meth:`Color.AlphaBlend`
139 - :meth:`Color.Blend`
140
141
142 Example usage
143 ---------------
144
145 To create an instance of the grapefruit.Color from RGB values:
146
147 >>> import grapefruit
148 >>> r, g, b = 1, 0.5, 0
149 >>> col = grapefruit.Color.NewFromRgb(r, g, b)
150
151 To get the values of the color in another colorspace:
152
153 >>> h, s, v = col.hsv
154 >>> l, a, b = col.lab
155
156 To get the complementary of a color:
157
158 >>> compl = col.ComplementaryColor()
159 >>> print compl.hsl
160 (210.0, 1.0, 0.5)
161
162 To directly convert RGB values to their HSL equivalent:
163
164 >>> h, s, l = Color.RgbToHsl(r, g, b)
165
166
167
168 .. _class-constants:
169
170 Class Constants
171 -----------------
172
173 .. data:: Color.WHITE_REFERENCE
174
175 The reference white points of the CIE standards illuminants, calculated from
176 the chromaticity coordinates found at:
177 http://en.wikipedia.org/wiki/Standard_illuminant
178
179 A dictionary mapping the name of the CIE standard illuminants to their reference
180 white points. The white points are required for the XYZ <-> L*a*b conversions.
181
182 The key names are build using the following pattern: ``<observer>_<illuminant>``
183
184 The possible values for ``<observer>`` are:
185
186 ====== ===================================
187 Value Observer
188 ====== ===================================
189 std CIE 1931 2° Standard Observer
190 sup CIE 1964 10° Supplementary Observer
191 ====== ===================================
192
193 The possible values for ``<illuminant>`` are the name of the standard illuminants:
194
195 ====== ======== ==================================================
196 Value CCT Illuminant
197 ====== ======== ==================================================
198 A 2856 K Incandescent tungsten
199 B 4874 K Direct sunlight at noon (obsolete)
200 C 6774 K North sky daylight (obsolete)
201 D50 5003 K ICC Profile PCS. Horizon light.
202 D55 5503 K Compromise between incandescent and daylight
203 D65 6504 K Noon daylight (TV & sRGB colorspace)
204 D75 7504 K North sky day light
205 E ~5455 K Equal energy radiator (not a black body)
206 F1 6430 K Daylight Fluorescent
207 F2 4230 K Cool White Fluorescent
208 F3 3450 K White Fluorescent
209 F4 2940 K Warm White Fluorescent
210 F5 6350 K Daylight Fluorescent
211 F6 4150 K Lite White Fluorescent
212 F7 6500 K Broadband fluorescent, D65 simulator
213 F8 5000 K Broadband fluorescent, D50 simulator
214 F9 4150 K Broadband fluorescent, Cool White Deluxe
215 F10 5000 K Narrowband fluorescent, Philips TL85, Ultralume 50
216 F11 4000 K Narrowband fluorescent, Philips TL84, Ultralume 40
217 F12 3000 K Narrowband fluorescent, Philips TL83, Ultralume 30
218 ====== ======== ==================================================
219
220 .. data:: Color.NAMED_COLOR
221
222 The names and RGB values of the X11 colors supported by popular browsers, with
223 the gray/grey spelling issues, fixed so that both work (e.g light*grey* and
224 light*gray*).
225
226 Note: For *Gray*, *Green*, *Maroon* and *Purple*, the HTML/CSS values are used
227 instead of the X11 ones
228 (see `X11/CSS clashes <http://en.wikipedia.org/wiki/X11_color_names#Color_names_that_clash_between_X11_and_HTML.2FCSS>`_)
229
230 Reference: `CSS3 Color module <http://www.w3.org/TR/css3-iccprof#x11-color>`_
231
232
233 .. _conversion-functions:
234
235 Conversion functions
236 --------------------
237
238 The conversion functions are static methods of the :class:`Color` class that
239 let you convert a color stored as the list of its components rather than
240 as a :class:`Color` instance.
241
242 .. automethod:: Color.RgbToHsl
243
244 .. automethod:: Color.HslToRgb
245
246 .. automethod:: Color.RgbToHsv
247
248 .. automethod:: Color.HsvToRgb
249
250 .. automethod:: Color.RgbToYiq
251
252 .. automethod:: Color.YiqToRgb
253
254 .. automethod:: Color.RgbToYuv
255
256 .. automethod:: Color.YuvToRgb
257
258 .. automethod:: Color.RgbToXyz
259
260 .. automethod:: Color.XyzToRgb
261
262 .. automethod:: Color.XyzToLab
263
264 .. automethod:: Color.LabToXyz
265
266 .. automethod:: Color.CmykToCmy
267
268 .. automethod:: Color.CmyToCmyk
269
270 .. automethod:: Color.RgbToCmy
271
272 .. automethod:: Color.CmyToRgb
273
274 .. automethod:: Color.RgbToHtml
275
276 .. automethod:: Color.HtmlToRgb
277
278 .. automethod:: Color.RgbToPil
279
280 .. automethod:: Color.PilToRgb
281
282 .. automethod:: Color.RgbToWebSafe
283
284 .. automethod:: Color.RgbToGreyscale
285
286 .. automethod:: Color.RgbToRyb
287
288 .. automethod:: Color.RybToRgb
289
290
291
292 .. _instantiation-functions:
293
294 Instantiation functions
295 -----------------------
296
297 The instantiation functions let you create a new instance of the :class:`Color`
298 class from the color components using the color system of your choice.
299
300 .. automethod:: Color.NewFromRgb
301
302 .. automethod:: Color.NewFromHsl
303
304 .. automethod:: Color.NewFromHsv
305
306 .. automethod:: Color.NewFromYiq
307
308 .. automethod:: Color.NewFromYuv
309
310 .. automethod:: Color.NewFromXyz
311
312 .. automethod:: Color.NewFromLab
313
314 .. automethod:: Color.NewFromCmy
315
316 .. automethod:: Color.NewFromCmyk
317
318 .. automethod:: Color.NewFromHtml
319
320 .. automethod:: Color.NewFromPil
321
322
323
324 .. _properties:
325
326 Properties
327 ----------
328
329 The properties get the value of the instance in the specified color model.
330
331 The properties returning calculated values unless marked otherwise.
332
333 .. note::
334
335 All the properties are read-only. You need to make a copy of the instance
336 to modify the color value.
337
338 .. autoattribute:: Color.alpha
339
340 *This value is not calculated, the stored value is returned directly.*
341
342 .. autoattribute:: Color.whiteRef
343
344 *This value is not calculated, the stored value is returned directly.*
345
346 .. autoattribute:: Color.rgb
347
348 *This value is not calculated, the stored value is returned directly.*
349
350 .. autoattribute:: Color.hue
351
352 *This value is not calculated, the stored value is returned directly.*
353
354 .. autoattribute:: Color.hsl
355
356 *This value is not calculated, the stored value is returned directly.*
357
358 .. autoattribute:: Color.hsv
359
360 .. autoattribute:: Color.yiq
361
362 .. autoattribute:: Color.yuv
363
364 .. autoattribute:: Color.xyz
365
366 .. autoattribute:: Color.lab
367
368 .. autoattribute:: Color.cmy
369
370 .. autoattribute:: Color.cmyk
371
372 .. autoattribute:: Color.html
373
374 .. autoattribute:: Color.pil
375
376 .. autoattribute:: Color.webSafe
377
378 .. attribute:: Color.greyscale
379
380
381
382 .. _manipulation-methods:
383
384 Manipulation methods
385 --------------------
386
387 The manipulations methods let you create a new color by changing an existing
388 color properties.
389
390 .. note::
391
392 The methods **do not** modify the current Color instance. They create a
393 new instance or a tuple of new instances with the specified modifications.
394
395 .. automethod:: Color.ColorWithAlpha
396
397 .. automethod:: Color.ColorWithWhiteRef
398
399 .. automethod:: Color.ColorWithHue
400
401 .. automethod:: Color.ColorWithSaturation
402
403 .. automethod:: Color.ColorWithLightness
404
405 .. automethod:: Color.DarkerColor
406
407 .. automethod:: Color.LighterColor
408
409 .. automethod:: Color.Saturate
410
411 .. automethod:: Color.Desaturate
412
413 .. automethod:: Color.WebSafeDither
414
415
416
417 .. _generation-methods:
418
419 Generation methods
420 ------------------
421
422 The generation methods let you create a color scheme by using a color as the
423 start point.
424
425 All the method, appart from Gradient and MonochromeScheme, have a 'mode'
426 parameter that let you choose which color wheel should be used to generate
427 the scheme.
428
429 The following modes are available:
430 :ryb:
431 The `RYB <http://en.wikipedia.org/wiki/RYB_color_model>`_ color wheel,
432 or *artistic color wheel*. While scientifically incorrect, it generally
433 produces better schemes than RGB.
434 :rgb:
435 The standard RGB color wheel.
436
437 .. automethod:: Color.Gradient
438
439 .. automethod:: Color.ComplementaryColor
440
441 .. automethod:: Color.MonochromeScheme
442
443 .. automethod:: Color.TriadicScheme
444
445 .. automethod:: Color.TetradicScheme
446
447 .. automethod:: Color.AnalogousScheme
448
449
450
451 .. _blending-methods:
452
453 Blending methods
454 ----------------
455
456 .. automethod:: Color.AlphaBlend
457
458 .. automethod:: Color.Blend
0 @echo off
1 set builder=%1
2 if [%builder%]==[] set builder=html
3 set target=_build\%builder%
4 if not exist %target%\* md %target%
5 sphinx-build -b %builder% . _build\%builder%\
6 set target=
7 set builder=
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 CHANGES
1 COPYING
2 LICENSE
3 README
4 TODO
5 grapefruit.py
6 grapefruit_test.py
7 setup.py
8 doc/Makefile
9 doc/conf.py
10 doc/index.rst
11 doc/makedoc.cmd
12 doc/_static/GrapeFruit.png
13 grapefruit.egg-info/PKG-INFO
14 grapefruit.egg-info/SOURCES.txt
15 grapefruit.egg-info/dependency_links.txt
16 grapefruit.egg-info/requires.txt
17 grapefruit.egg-info/top_level.txt
18 grapefruit.egg-info/zip-safe
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 '''GrapeFruit - Color manipulation in Python'''
18
19 # $Id: grapefruit.py 30 2008-06-01 20:44:26Z xbasty $
20 __author__ = 'Xavier Basty <xbasty@gmail.com>'
21 __version__ = '0.1a3'
22
23
24 # The default white reference, use 2° Standard Observer, D65 (daylight)
25 _DEFAULT_WREF = (0.95043, 1.00000, 1.08890)
26
27 _oneThird = 1.0 / 3
28 _srgbGammaCorrInv = 0.03928 / 12.92
29 _sixteenHundredsixteenth = 16.0 / 116
30
31 _RybWheel = (
32 0, 26, 52,
33 83, 120, 130,
34 141, 151, 162,
35 177, 190, 204,
36 218, 232, 246,
37 261, 275, 288,
38 303, 317, 330,
39 338, 345, 352,
40 360)
41
42 _RgbWheel = (
43 0, 8, 17,
44 26, 34, 41,
45 48, 54, 60,
46 81, 103, 123,
47 138, 155, 171,
48 187, 204, 219,
49 234, 251, 267,
50 282, 298, 329,
51 360)
52
53 class Color:
54 '''Hold a color value.
55
56 Example usage:
57
58 To create an instance of the grapefruit.Color from RGB values:
59
60 >>> import grapefruit
61 >>> r, g, b = 1, 0.5, 0
62 >>> col = grapefruit.Color.NewFromRgb(r, g, b)
63
64 To get the values of the color in another colorspace:
65
66 >>> h, s, v = col.hsv
67 >>> l, a, b = col.lab
68
69 To get the complementary of a color:
70
71 >>> compl = col.ComplementaryColor()
72 >>> print compl.hsl
73 (210.0, 1.0, 0.5)
74
75 To directly convert RGB values to their HSL equivalent:
76
77 >>> h, s, l = Color.RgbToHsl(r, g, b)
78
79 '''
80
81 WHITE_REFERENCE = {
82 'std_A' : (1.09847, 1.00000, 0.35582),
83 'std_B' : (0.99093, 1.00000, 0.85313),
84 'std_C' : (0.98071, 1.00000, 1.18225),
85 'std_D50' : (0.96421, 1.00000, 0.82519),
86 'std_D55' : (0.95680, 1.00000, 0.92148),
87 'std_D65' : (0.95043, 1.00000, 1.08890),
88 'std_D75' : (0.94972, 1.00000, 1.22639),
89 'std_E' : (1.00000, 1.00000, 1.00000),
90 'std_F1' : (0.92834, 1.00000, 1.03665),
91 'std_F2' : (0.99145, 1.00000, 0.67316),
92 'std_F3' : (1.03753, 1.00000, 0.49861),
93 'std_F4' : (1.09147, 1.00000, 0.38813),
94 'std_F5' : (0.90872, 1.00000, 0.98723),
95 'std_F6' : (0.97309, 1.00000, 0.60191),
96 'std_F7' : (0.95017, 1.00000, 1.08630),
97 'std_F8' : (0.96413, 1.00000, 0.82333),
98 'std_F9' : (1.00365, 1.00000, 0.67868),
99 'std_F10' : (0.96174, 1.00000, 0.81712),
100 'std_F11' : (1.00899, 1.00000, 0.64262),
101 'std_F12' : (1.08046, 1.00000, 0.39228),
102 'sup_A' : (1.11142, 1.00000, 0.35200),
103 'sup_B' : (0.99178, 1.00000, 0.84349),
104 'sup_C' : (0.97286, 1.00000, 1.16145),
105 'sup_D50' : (0.96721, 1.00000, 0.81428),
106 'sup_D55' : (0.95797, 1.00000, 0.90925),
107 'sup_D65' : (0.94810, 1.00000, 1.07305),
108 'sup_D75' : (0.94417, 1.00000, 1.20643),
109 'sup_E' : (1.00000, 1.00000, 1.00000),
110 'sup_F1' : (0.94791, 1.00000, 1.03191),
111 'sup_F2' : (1.03245, 1.00000, 0.68990),
112 'sup_F3' : (1.08968, 1.00000, 0.51965),
113 'sup_F4' : (1.14961, 1.00000, 0.40963),
114 'sup_F5' : (0.93369, 1.00000, 0.98636),
115 'sup_F6' : (1.02148, 1.00000, 0.62074),
116 'sup_F7' : (0.95780, 1.00000, 1.07618),
117 'sup_F8' : (0.97115, 1.00000, 0.81135),
118 'sup_F9' : (1.02116, 1.00000, 0.67826),
119 'sup_F10' : (0.99001, 1.00000, 0.83134),
120 'sup_F11' : (1.03820, 1.00000, 0.65555),
121 'sup_F12' : (1.11428, 1.00000, 0.40353)}
122
123 NAMED_COLOR = {
124 'aliceblue': '#f0f8ff',
125 'antiquewhite': '#faebd7',
126 'aqua': '#00ffff',
127 'aquamarine': '#7fffd4',
128 'azure': '#f0ffff',
129 'beige': '#f5f5dc',
130 'bisque': '#ffe4c4',
131 'black': '#000000',
132 'blanchedalmond': '#ffebcd',
133 'blue': '#0000ff',
134 'blueviolet': '#8a2be2',
135 'brown': '#a52a2a',
136 'burlywood': '#deb887',
137 'cadetblue': '#5f9ea0',
138 'chartreuse': '#7fff00',
139 'chocolate': '#d2691e',
140 'coral': '#ff7f50',
141 'cornflowerblue': '#6495ed',
142 'cornsilk': '#fff8dc',
143 'crimson': '#dc143c',
144 'cyan': '#00ffff',
145 'darkblue': '#00008b',
146 'darkcyan': '#008b8b',
147 'darkgoldenrod': '#b8860b',
148 'darkgray': '#a9a9a9',
149 'darkgrey': '#a9a9a9',
150 'darkgreen': '#006400',
151 'darkkhaki': '#bdb76b',
152 'darkmagenta': '#8b008b',
153 'darkolivegreen': '#556b2f',
154 'darkorange': '#ff8c00',
155 'darkorchid': '#9932cc',
156 'darkred': '#8b0000',
157 'darksalmon': '#e9967a',
158 'darkseagreen': '#8fbc8f',
159 'darkslateblue': '#483d8b',
160 'darkslategray': '#2f4f4f',
161 'darkslategrey': '#2f4f4f',
162 'darkturquoise': '#00ced1',
163 'darkviolet': '#9400d3',
164 'deeppink': '#ff1493',
165 'deepskyblue': '#00bfff',
166 'dimgray': '#696969',
167 'dimgrey': '#696969',
168 'dodgerblue': '#1e90ff',
169 'firebrick': '#b22222',
170 'floralwhite': '#fffaf0',
171 'forestgreen': '#228b22',
172 'fuchsia': '#ff00ff',
173 'gainsboro': '#dcdcdc',
174 'ghostwhite': '#f8f8ff',
175 'gold': '#ffd700',
176 'goldenrod': '#daa520',
177 'gray': '#808080',
178 'grey': '#808080',
179 'green': '#008000',
180 'greenyellow': '#adff2f',
181 'honeydew': '#f0fff0',
182 'hotpink': '#ff69b4',
183 'indianred': '#cd5c5c',
184 'indigo': '#4b0082',
185 'ivory': '#fffff0',
186 'khaki': '#f0e68c',
187 'lavender': '#e6e6fa',
188 'lavenderblush': '#fff0f5',
189 'lawngreen': '#7cfc00',
190 'lemonchiffon': '#fffacd',
191 'lightblue': '#add8e6',
192 'lightcoral': '#f08080',
193 'lightcyan': '#e0ffff',
194 'lightgoldenrodyellow': '#fafad2',
195 'lightgreen': '#90ee90',
196 'lightgray': '#d3d3d3',
197 'lightgrey': '#d3d3d3',
198 'lightpink': '#ffb6c1',
199 'lightsalmon': '#ffa07a',
200 'lightseagreen': '#20b2aa',
201 'lightskyblue': '#87cefa',
202 'lightslategray': '#778899',
203 'lightslategrey': '#778899',
204 'lightsteelblue': '#b0c4de',
205 'lightyellow': '#ffffe0',
206 'lime': '#00ff00',
207 'limegreen': '#32cd32',
208 'linen': '#faf0e6',
209 'magenta': '#ff00ff',
210 'maroon': '#800000',
211 'mediumaquamarine': '#66cdaa',
212 'mediumblue': '#0000cd',
213 'mediumorchid': '#ba55d3',
214 'mediumpurple': '#9370db',
215 'mediumseagreen': '#3cb371',
216 'mediumslateblue': '#7b68ee',
217 'mediumspringgreen': '#00fa9a',
218 'mediumturquoise': '#48d1cc',
219 'mediumvioletred': '#c71585',
220 'midnightblue': '#191970',
221 'mintcream': '#f5fffa',
222 'mistyrose': '#ffe4e1',
223 'moccasin': '#ffe4b5',
224 'navajowhite': '#ffdead',
225 'navy': '#000080',
226 'oldlace': '#fdf5e6',
227 'olive': '#808000',
228 'olivedrab': '#6b8e23',
229 'orange': '#ffa500',
230 'orangered': '#ff4500',
231 'orchid': '#da70d6',
232 'palegoldenrod': '#eee8aa',
233 'palegreen': '#98fb98',
234 'paleturquoise': '#afeeee',
235 'palevioletred': '#db7093',
236 'papayawhip': '#ffefd5',
237 'peachpuff': '#ffdab9',
238 'peru': '#cd853f',
239 'pink': '#ffc0cb',
240 'plum': '#dda0dd',
241 'powderblue': '#b0e0e6',
242 'purple': '#800080',
243 'red': '#ff0000',
244 'rosybrown': '#bc8f8f',
245 'royalblue': '#4169e1',
246 'saddlebrown': '#8b4513',
247 'salmon': '#fa8072',
248 'sandybrown': '#f4a460',
249 'seagreen': '#2e8b57',
250 'seashell': '#fff5ee',
251 'sienna': '#a0522d',
252 'silver': '#c0c0c0',
253 'skyblue': '#87ceeb',
254 'slateblue': '#6a5acd',
255 'slategray': '#708090',
256 'slategrey': '#708090',
257 'snow': '#fffafa',
258 'springgreen': '#00ff7f',
259 'steelblue': '#4682b4',
260 'tan': '#d2b48c',
261 'teal': '#008080',
262 'thistle': '#d8bfd8',
263 'tomato': '#ff6347',
264 'turquoise': '#40e0d0',
265 'violet': '#ee82ee',
266 'wheat': '#f5deb3',
267 'white': '#ffffff',
268 'whitesmoke': '#f5f5f5',
269 'yellow': '#ffff00',
270 'yellowgreen': '#9acd32'}
271
272 def __init__(self, values, mode='rgb', alpha=1.0, wref=_DEFAULT_WREF):
273 '''Instantiate a new grapefruit.Color object.
274
275 Parameters:
276 :values:
277 The values of this color, in the specified representation.
278 :mode:
279 The representation mode used for values.
280 :alpha:
281 the alpha value (transparency) of this color.
282 :wref:
283 The whitepoint reference, default is 2° D65.
284
285 '''
286 if not(isinstance(values, tuple)):
287 raise TypeError, 'values must be a tuple'
288
289 if mode=='rgb':
290 self.__rgb = values
291 self.__hsl = Color.RgbToHsl(*values)
292 elif mode=='hsl':
293 self.__hsl = values
294 self.__rgb = Color.HslToRgb(*values)
295 else:
296 raise ValueError('Invalid color mode: ' + mode)
297
298 self.__a = alpha
299 self.__wref = wref
300
301 def __ne__(self, other):
302 return not self.__eq__(other)
303
304 def __eq__(self, other):
305 try:
306 if isinstance(other, Color):
307 return (self.__rgb==other.__rgb) and (self.__a==other.__a)
308
309 if len(other) != 4:
310 return False
311 rgba = self.__rgb + (self.__a,)
312 return reduce(lambda x, y: x and (y[0]==y[1]), zip(rgba, other), True)
313 except TypeError:
314 return False
315 except AttributeError:
316 return False
317
318 def __repr__(self):
319 return str(self.__rgb + (self.__a,))
320
321 def __str__(self):
322 '''A string representation of this grapefruit.Color instance.
323
324 Returns:
325 The RGBA representation of this grapefruit.Color instance.
326
327 '''
328 return '(%g, %g, %g, %g)' % (self.__rgb + (self.__a,))
329
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,))
338
339 def __iter__(self):
340 return iter(self.__rgb + (self.__a,))
341
342 def __len__(self):
343 return 4
344
345 @staticmethod
346 def RgbToHsl(r, g, b):
347 '''Convert the color from RGB coordinates to HSL.
348
349 Parameters:
350 :r:
351 The Red component value [0...1]
352 :g:
353 The Green component value [0...1]
354 :b:
355 The Blue component value [0...1]
356
357 Returns:
358 The color as an (h, s, l) tuple in the range:
359 h[0...360],
360 s[0...1],
361 l[0...1]
362
363 >>> Color.RgbToHsl(1, 0.5, 0)
364 (30.0, 1.0, 0.5)
365
366 '''
367 minVal = min(r, g, b) # min RGB value
368 maxVal = max(r, g, b) # max RGB value
369
370 l = (maxVal + minVal) / 2.0
371 if minVal==maxVal:
372 return (0.0, 0.0, l) # achromatic (gray)
373
374 d = maxVal - minVal # delta RGB value
375
376 if l < 0.5: s = d / (maxVal + minVal)
377 else: s = d / (2.0 - maxVal - minVal)
378
379 dr, dg, db = [(maxVal-val) / d for val in (r, g, b)]
380
381 if r==maxVal:
382 h = db - dg
383 elif g==maxVal:
384 h = 2.0 + dr - db
385 else:
386 h = 4.0 + dg - dr
387
388 h = (h*60.0) % 360.0
389 return (h, s, l)
390
391 @staticmethod
392 def _HueToRgb(n1, n2, h):
393 h %= 6.0
394 if h < 1.0: return n1 + ((n2-n1) * h)
395 if h < 3.0: return n2
396 if h < 4.0: return n1 + ((n2-n1) * (4.0 - h))
397 return n1
398
399 @staticmethod
400 def HslToRgb(h, s, l):
401 '''Convert the color from HSL coordinates to RGB.
402
403 Parameters:
404 :h:
405 The Hue component value [0...1]
406 :s:
407 The Saturation component value [0...1]
408 :l:
409 The Lightness component value [0...1]
410
411 Returns:
412 The color as an (r, g, b) tuple in the range:
413 r[0...1],
414 g[0...1],
415 b[0...1]
416
417 >>> Color.HslToRgb(30.0, 1.0, 0.5)
418 (1.0, 0.5, 0.0)
419
420 '''
421 if s==0: return (l, l, l) # achromatic (gray)
422
423 if l<0.5: n2 = l * (1.0 + s)
424 else: n2 = l+s - (l*s)
425
426 n1 = (2.0 * l) - n2
427
428 h /= 60.0
429 hueToRgb = Color._HueToRgb
430 r = hueToRgb(n1, n2, h + 2)
431 g = hueToRgb(n1, n2, h)
432 b = hueToRgb(n1, n2, h - 2)
433
434 return (r, g, b)
435
436 @staticmethod
437 def RgbToHsv(r, g, b):
438 '''Convert the color from RGB coordinates to HSV.
439
440 Parameters:
441 :r:
442 The Red component value [0...1]
443 :g:
444 The Green component value [0...1]
445 :b:
446 The Blue component value [0...1]
447
448 Returns:
449 The color as an (h, s, v) tuple in the range:
450 h[0...360],
451 s[0...1],
452 v[0...1]
453
454 >>> 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)
460 if d==0: return (0.0, 0.0, v)
461 s = d / v
462
463 dr, dg, db = [(v - val) / d for val in (r, g, b)]
464
465 if r==v:
466 h = db - dg # between yellow & magenta
467 elif g==v:
468 h = 2.0 + dr - db # between cyan & yellow
469 else: # b==v
470 h = 4.0 + dg - dr # between magenta & cyan
471
472 h = (h*60.0) % 360.0
473 return (h, s, v)
474
475 @staticmethod
476 def HsvToRgb(h, s, v):
477 '''Convert the color from RGB coordinates to HSV.
478
479 Parameters:
480 :h:
481 The Hus component value [0...1]
482 :s:
483 The Saturation component value [0...1]
484 :v:
485 The Value component [0...1]
486
487 Returns:
488 The color as an (r, g, b) tuple in the range:
489 r[0...1],
490 g[0...1],
491 b[0...1]
492
493 >>> Color.HslToRgb(30.0, 1.0, 0.5)
494 (1.0, 0.5, 0.0)
495
496 '''
497 if s==0: return (v, v, v) # achromatic (gray)
498
499 h /= 60.0
500 h = h % 6.0
501
502 i = int(h)
503 f = h - i
504 if not(i&1): f = 1-f # if i is even
505
506 m = v * (1.0 - s)
507 n = v * (1.0 - (s * f))
508
509 if i==0: return (v, n, m)
510 if i==1: return (n, v, m)
511 if i==2: return (m, v, n)
512 if i==3: return (m, n, v)
513 if i==4: return (n, m, v)
514 return (v, m, n)
515
516 @staticmethod
517 def RgbToYiq(r, g, b):
518 '''Convert the color from RGB to YIQ.
519
520 Parameters:
521 :r:
522 The Red component value [0...1]
523 :g:
524 The Green component value [0...1]
525 :b:
526 The Blue component value [0...1]
527
528 Returns:
529 The color as an (y, i, q) tuple in the range:
530 y[0...1],
531 i[0...1],
532 q[0...1]
533
534 >>> '(%g, %g, %g)' % Color.RgbToYiq(1, 0.5, 0)
535 '(0.592263, 0.458874, -0.0499818)'
536
537 '''
538 y = (r * 0.29895808) + (g * 0.58660979) + (b *0.11443213)
539 i = (r * 0.59590296) - (g * 0.27405705) - (b *0.32184591)
540 q = (r * 0.21133576) - (g * 0.52263517) + (b *0.31129940)
541 return (y, i, q)
542
543 @staticmethod
544 def YiqToRgb(y, i, q):
545 '''Convert the color from YIQ coordinates to RGB.
546
547 Parameters:
548 :y:
549 Tte Y component value [0...1]
550 :i:
551 The I component value [0...1]
552 :q:
553 The Q component value [0...1]
554
555 Returns:
556 The color as an (r, g, b) tuple in the range:
557 r[0...1],
558 g[0...1],
559 b[0...1]
560
561 >>> '(%g, %g, %g)' % Color.YiqToRgb(0.592263, 0.458874, -0.0499818)
562 '(1, 0.5, 5.442e-007)'
563
564 '''
565 r = y + (i * 0.9562) + (q * 0.6210)
566 g = y - (i * 0.2717) - (q * 0.6485)
567 b = y - (i * 1.1053) + (q * 1.7020)
568 return (r, g, b)
569
570 @staticmethod
571 def RgbToYuv(r, g, b):
572 '''Convert the color from RGB coordinates to YUV.
573
574 Parameters:
575 :r:
576 The Red component value [0...1]
577 :g:
578 The Green component value [0...1]
579 :b:
580 The Blue component value [0...1]
581
582 Returns:
583 The color as an (y, u, v) tuple in the range:
584 y[0...1],
585 u[-0.436...0.436],
586 v[-0.615...0.615]
587
588 >>> '(%g, %g, %g)' % Color.RgbToYuv(1, 0.5, 0)
589 '(0.5925, -0.29156, 0.357505)'
590
591 '''
592 y = (r * 0.29900) + (g * 0.58700) + (b * 0.11400)
593 u = -(r * 0.14713) - (g * 0.28886) + (b * 0.43600)
594 v = (r * 0.61500) - (g * 0.51499) - (b * 0.10001)
595 return (y, u, v)
596
597 @staticmethod
598 def YuvToRgb(y, u, v):
599 '''Convert the color from YUV coordinates to RGB.
600
601 Parameters:
602 :y:
603 The Y component value [0...1]
604 :u:
605 The U component value [-0.436...0.436]
606 :v:
607 The V component value [-0.615...0.615]
608
609 Returns:
610 The color as an (r, g, b) tuple in the range:
611 r[0...1],
612 g[0...1],
613 b[0...1]
614
615 >>> '(%g, %g, %g)' % Color.YuvToRgb(0.5925, -0.2916, 0.3575)
616 '(0.999989, 0.500015, -6.3276e-005)'
617
618 '''
619 r = y + (v * 1.13983)
620 g = y - (u * 0.39465) - (v * 0.58060)
621 b = y + (u * 2.03211)
622 return (r, g, b)
623
624 @staticmethod
625 def RgbToXyz(r, g, b):
626 '''Convert the color from sRGB to CIE XYZ.
627
628 The methods assumes that the RGB coordinates are given in the sRGB
629 colorspace (D65).
630
631 .. note::
632
633 Compensation for the sRGB gamma correction is applied before converting.
634
635 Parameters:
636 :r:
637 The Red component value [0...1]
638 :g:
639 The Green component value [0...1]
640 :b:
641 The Blue component value [0...1]
642
643 Returns:
644 The color as an (x, y, z) tuple in the range:
645 x[0...1],
646 y[0...1],
647 z[0...1]
648
649 >>> '(%g, %g, %g)' % Color.RgbToXyz(1, 0.5, 0)
650 '(0.488941, 0.365682, 0.0448137)'
651
652 '''
653 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
655 x = (r * 0.4124) + (g * 0.3576) + (b * 0.1805)
656 y = (r * 0.2126) + (g * 0.7152) + (b * 0.0722)
657 z = (r * 0.0193) + (g * 0.1192) + (b * 0.9505)
658 return (x, y, z)
659
660 @staticmethod
661 def XyzToRgb(x, y, z):
662 '''Convert the color from CIE XYZ coordinates to sRGB.
663
664 .. note::
665
666 Compensation for sRGB gamma correction is applied before converting.
667
668 Parameters:
669 :x:
670 The X component value [0...1]
671 :y:
672 The Y component value [0...1]
673 :z:
674 The Z component value [0...1]
675
676 Returns:
677 The color as an (r, g, b) tuple in the range:
678 r[0...1],
679 g[0...1],
680 b[0...1]
681
682 >>> '(%g, %g, %g)' % Color.XyzToRgb(0.488941, 0.365682, 0.0448137)
683 '(1, 0.5, 6.81883e-008)'
684
685 '''
686 r = (x * 3.2406255) - (y * 1.5372080) - (z * 0.4986286)
687 g = -(x * 0.9689307) + (y * 1.8757561) + (z * 0.0415175)
688 b = (x * 0.0557101) - (y * 0.2040211) + (z * 1.0569959)
689 return tuple((((v <= _srgbGammaCorrInv) and [v * 12.92] or [(1.055 * (v ** (1/2.4))) - 0.055])[0] for v in (r, g, b)))
690
691 @staticmethod
692 def XyzToLab(x, y, z, wref=_DEFAULT_WREF):
693 '''Convert the color from CIE XYZ to CIE L*a*b*.
694
695 Parameters:
696 :x:
697 The X component value [0...1]
698 :y:
699 The Y component value [0...1]
700 :z:
701 The Z component value [0...1]
702 :wref:
703 The whitepoint reference, default is 2° D65.
704
705 Returns:
706 The color as an (L, a, b) tuple in the range:
707 L[0...100],
708 a[-1...1],
709 b[-1...1]
710
711 >>> '(%g, %g, %g)' % Color.XyzToLab(0.488941, 0.365682, 0.0448137)
712 '(66.9518, 0.43084, 0.739692)'
713
714 >>> '(%g, %g, %g)' % Color.XyzToLab(0.488941, 0.365682, 0.0448137, Color.WHITE_REFERENCE['std_D50'])
715 '(66.9518, 0.411663, 0.67282)'
716
717 '''
718 # White point correction
719 x /= wref[0]
720 y /= wref[1]
721 z /= wref[2]
722
723 # Nonlinear distortion and linear transformation
724 x, y, z = [((v > 0.008856) and [v**_oneThird] or [(7.787 * v) + _sixteenHundredsixteenth])[0] for v in (x, y, z)]
725
726 # Vector scaling
727 l = (116 * y) - 16
728 a = 5.0 * (x - y)
729 b = 2.0 * (y - z)
730
731 return (l, a, b)
732
733 @staticmethod
734 def LabToXyz(l, a, b, wref=_DEFAULT_WREF):
735 '''Convert the color from CIE L*a*b* to CIE 1931 XYZ.
736
737 Parameters:
738 :l:
739 The L component [0...100]
740 :a:
741 The a component [-1...1]
742 :b:
743 The a component [-1...1]
744 :wref:
745 The whitepoint reference, default is 2° D65.
746
747 Returns:
748 The color as an (x, y, z) tuple in the range:
749 x[0...q],
750 y[0...1],
751 z[0...1]
752
753 >>> '(%g, %g, %g)' % Color.LabToXyz(66.9518, 0.43084, 0.739692)
754 '(0.488941, 0.365682, 0.0448137)'
755
756 >>> '(%g, %g, %g)' % Color.LabToXyz(66.9518, 0.411663, 0.67282, Color.WHITE_REFERENCE['std_D50'])
757 '(0.488941, 0.365682, 0.0448138)'
758
759 '''
760 y = (l + 16) / 116
761 x = (a / 5.0) + y
762 z = y - (b / 2.0)
763 return tuple((((v > 0.206893) and [v**3] or [(v - _sixteenHundredsixteenth) / 7.787])[0] * w for v, w in zip((x, y, z), wref)))
764
765 @staticmethod
766 def CmykToCmy(c, m, y, k):
767 '''Convert the color from CMYK coordinates to CMY.
768
769 Parameters:
770 :c:
771 The Cyan component value [0...1]
772 :m:
773 The Magenta component value [0...1]
774 :y:
775 The Yellow component value [0...1]
776 :k:
777 The Black component value [0...1]
778
779 Returns:
780 The color as an (c, m, y) tuple in the range:
781 c[0...1],
782 m[0...1],
783 y[0...1]
784
785 >>> '(%g, %g, %g)' % Color.CmykToCmy(1, 0.32, 0, 0.5)
786 '(1, 0.66, 0.5)'
787
788 '''
789 mk = 1-k
790 return ((c*mk + k), (m*mk + k), (y*mk + k))
791
792 @staticmethod
793 def CmyToCmyk(c, m, y):
794 '''Convert the color from CMY coordinates to CMYK.
795
796 Parameters:
797 :c:
798 The Cyan component value [0...1]
799 :m:
800 The Magenta component value [0...1]
801 :y:
802 The Yellow component value [0...1]
803
804 Returns:
805 The color as an (c, m, y, k) tuple in the range:
806 c[0...1],
807 m[0...1],
808 y[0...1],
809 k[0...1]
810
811 >>> '(%g, %g, %g, %g)' % Color.CmyToCmyk(1, 0.66, 0.5)
812 '(1, 0.32, 0, 0.5)'
813
814 '''
815 k = min(c, m, y)
816 if k==1.0: return (0.0, 0.0, 0.0, 1.0)
817 mk = 1-k
818 return ((c-k) / mk, (m-k) / mk, (y-k) / mk, k)
819
820 @staticmethod
821 def RgbToCmy(r, g, b):
822 '''Convert the color from RGB coordinates to CMY.
823
824 Parameters:
825 :r:
826 The Red component value [0...1]
827 :g:
828 The Green component value [0...1]
829 :b:
830 The Blue component value [0...1]
831
832 Returns:
833 The color as an (c, m, y) tuple in the range:
834 c[0...1],
835 m[0...1],
836 y[0...1]
837
838 >>> Color.RgbToCmy(1, 0.5, 0)
839 (0, 0.5, 1)
840
841 '''
842 return (1-r, 1-g, 1-b)
843
844 @staticmethod
845 def CmyToRgb(c, m, y):
846 '''Convert the color from CMY coordinates to RGB.
847
848 Parameters:
849 :c:
850 The Cyan component value [0...1]
851 :m:
852 The Magenta component value [0...1]
853 :y:
854 The Yellow component value [0...1]
855
856 Returns:
857 The color as an (r, g, b) tuple in the range:
858 r[0...1],
859 g[0...1],
860 b[0...1]
861
862 >>> Color.CmyToRgb(0, 0.5, 1)
863 (1, 0.5, 0)
864
865 '''
866 return (1-c, 1-m, 1-y)
867
868 @staticmethod
869 def RgbToHtml(r, g, b):
870 '''Convert the color from (r, g, b) to #RRGGBB.
871
872 Parameters:
873 :r:
874 The Red component value [0...1]
875 :g:
876 The Green component value [0...1]
877 :b:
878 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 Returns:
898 The color as an (r, g, b) tuple in the range:
899 r[0...1],
900 g[0...1],
901 b[0...1]
902
903 Throws:
904 :ValueError:
905 If html is neither a known color name or a hexadecimal RGB
906 representation.
907
908 >>> '(%g, %g, %g)' % Color.HtmlToRgb('#ff8000')
909 '(1, 0.501961, 0)'
910 >>> '(%g, %g, %g)' % Color.HtmlToRgb('ff8000')
911 '(1, 0.501961, 0)'
912 >>> '(%g, %g, %g)' % Color.HtmlToRgb('#f60')
913 '(1, 0.4, 0)'
914 >>> '(%g, %g, %g)' % Color.HtmlToRgb('f60')
915 '(1, 0.4, 0)'
916 >>> '(%g, %g, %g)' % Color.HtmlToRgb('lemonchiffon')
917 '(1, 0.980392, 0.803922)'
918
919 '''
920 html = html.strip().lower()
921 if html[0]=='#':
922 html = html[1:]
923 elif Color.NAMED_COLOR.has_key(html):
924 html = Color.NAMED_COLOR[html][1:]
925
926 if len(html)==6:
927 rgb = html[:2], html[2:4], html[4:]
928 elif len(html)==3:
929 rgb = ['%c%c' % (v,v) for v in html]
930 else:
931 raise ValueError, 'input #%s is not in #RRGGBB format' % html
932
933 return tuple(((int(n, 16) / 255.0) for n in rgb))
934
935 @staticmethod
936 def RgbToPil(r, g, b):
937 '''Convert the color from RGB to a PIL-compatible integer.
938
939 Parameters:
940 :r:
941 The Red component value [0...1]
942 :g:
943 The Green component value [0...1]
944 :b:
945 The Blue component value [0...1]
946
947 Returns:
948 A PIL compatible integer (0xBBGGRR).
949
950 >>> '0x%06x' % Color.RgbToPil(1, 0.5, 0)
951 '0x0080ff'
952
953 '''
954 r, g, b = [min(int(round(v*255)), 255) for v in (r, g, b)]
955 return (b << 16) + (g << 8) + r
956
957 @staticmethod
958 def PilToRgb(pil):
959 '''Convert the color from a PIL-compatible integer to RGB.
960
961 Parameters:
962 pil: a PIL compatible color representation (0xBBGGRR)
963 Returns:
964 The color as an (r, g, b) tuple in the range:
965 the range:
966 r: [0...1]
967 g: [0...1]
968 b: [0...1]
969
970 >>> '(%g, %g, %g)' % Color.PilToRgb(0x0080ff)
971 '(1, 0.501961, 0)'
972
973 '''
974 r = 0xff & pil
975 g = 0xff & (pil >> 8)
976 b = 0xff & (pil >> 16)
977 return tuple((v / 255.0 for v in (r, g, b)))
978
979 @staticmethod
980 def _WebSafeComponent(c, alt=False):
981 '''Convert a color component to its web safe equivalent.
982
983 Parameters:
984 :c:
985 The component value [0...1]
986 :alt:
987 If True, return the alternative value instead of the nearest one.
988
989 Returns:
990 The web safe equivalent of the component value.
991
992 '''
993 # This sucks, but floating point between 0 and 1 is quite fuzzy...
994 # So we just change the scale a while to make the equality tests
995 # work, otherwise it gets wrong at some decimal far to the right.
996 sc = c * 100.0
997
998 # If the color is already safe, return it straight away
999 d = sc % 20
1000 if d==0: return c
1001
1002 # Get the lower and upper safe values
1003 l = sc - d
1004 u = l + 20
1005
1006 # Return the 'closest' value according to the alt flag
1007 if alt:
1008 if (sc-l) >= (u-sc): return l/100.0
1009 else: return u/100.0
1010 else:
1011 if (sc-l) >= (u-sc): return u/100.0
1012 else: return l/100.0
1013
1014 @staticmethod
1015 def RgbToWebSafe(r, g, b, alt=False):
1016 '''Convert the color from RGB to 'web safe' RGB
1017
1018 Parameters:
1019 :r:
1020 The Red component value [0...1]
1021 :g:
1022 The Green component value [0...1]
1023 :b:
1024 The Blue component value [0...1]
1025 :alt:
1026 If True, use the alternative color instead of the nearest one.
1027 Can be used for dithering.
1028
1029 Returns:
1030 The color as an (r, g, b) tuple in the range:
1031 the range:
1032 r[0...1],
1033 g[0...1],
1034 b[0...1]
1035
1036 >>> '(%g, %g, %g)' % Color.RgbToWebSafe(1, 0.55, 0.0)
1037 '(1, 0.6, 0)'
1038
1039 '''
1040 webSafeComponent = Color._WebSafeComponent
1041 return tuple((webSafeComponent(v, alt) for v in (r, g, b)))
1042
1043 @staticmethod
1044 def RgbToGreyscale(r, g, b):
1045 '''Convert the color from RGB to its greyscale equivalent
1046
1047 Parameters:
1048 :r:
1049 The Red component value [0...1]
1050 :g:
1051 The Green component value [0...1]
1052 :b:
1053 The Blue component value [0...1]
1054
1055 Returns:
1056 The color as an (r, g, b) tuple in the range:
1057 the range:
1058 r[0...1],
1059 g[0...1],
1060 b[0...1]
1061
1062 >>> '(%g, %g, %g)' % Color.RgbToGreyscale(1, 0.8, 0)
1063 '(0.6, 0.6, 0.6)'
1064
1065 '''
1066 v = (r + g + b) / 3.0
1067 return (v, v, v)
1068
1069 @staticmethod
1070 def RgbToRyb(hue):
1071 '''Maps a hue on the RGB color wheel to Itten's RYB wheel.
1072
1073 Parameters:
1074 :hue:
1075 The hue on the RGB color wheel [0...360]
1076
1077 Returns:
1078 An approximation of the corresponding hue on Itten's RYB wheel.
1079
1080 >>> Color.RgbToRyb(15)
1081 26
1082
1083 '''
1084 d = hue % 15
1085 i = int(hue / 15)
1086 x0 = _RybWheel[i]
1087 x1 = _RybWheel[i+1]
1088 return x0 + (x1-x0) * d / 15
1089
1090 @staticmethod
1091 def RybToRgb(hue):
1092 '''Maps a hue on Itten's RYB color wheel to the standard RGB wheel.
1093
1094 Parameters:
1095 :hue:
1096 The hue on Itten's RYB color wheel [0...360]
1097
1098 Returns:
1099 An approximation of the corresponding hue on the standard RGB wheel.
1100
1101 >>> Color.RybToRgb(15)
1102 8
1103
1104 '''
1105 d = hue % 15
1106 i = int(hue / 15)
1107 x0 = _RgbWheel[i]
1108 x1 = _RgbWheel[i+1]
1109 return x0 + (x1-x0) * d / 15
1110
1111 @staticmethod
1112 def NewFromRgb(r, g, b, alpha=1.0, wref=_DEFAULT_WREF):
1113 '''Create a new instance based on the specifed RGB values.
1114
1115 Parameters:
1116 :r:
1117 The Red component value [0...1]
1118 :g:
1119 The Green component value [0...1]
1120 :b:
1121 The Blue component value [0...1]
1122 :alpha:
1123 The color transparency [0...1], default is opaque
1124 :wref:
1125 The whitepoint reference, default is 2° D65.
1126
1127 Returns:
1128 A grapefruit.Color instance.
1129
1130 >>> Color.NewFromRgb(1.0, 0.5, 0.0)
1131 (1.0, 0.5, 0.0, 1.0)
1132 >>> Color.NewFromRgb(1.0, 0.5, 0.0, 0.5)
1133 (1.0, 0.5, 0.0, 0.5)
1134
1135 '''
1136 return Color((r, g, b), 'rgb', alpha, wref)
1137
1138 @staticmethod
1139 def NewFromHsl(h, s, l, alpha=1.0, wref=_DEFAULT_WREF):
1140 '''Create a new instance based on the specifed HSL values.
1141
1142 Parameters:
1143 :h:
1144 The Hue component value [0...1]
1145 :s:
1146 The Saturation component value [0...1]
1147 :l:
1148 The Lightness component value [0...1]
1149 :alpha:
1150 The color transparency [0...1], default is opaque
1151 :wref:
1152 The whitepoint reference, default is 2° D65.
1153
1154 Returns:
1155 A grapefruit.Color instance.
1156
1157 >>> Color.NewFromHsl(30, 1, 0.5)
1158 (1.0, 0.5, 0.0, 1.0)
1159 >>> Color.NewFromHsl(30, 1, 0.5, 0.5)
1160 (1.0, 0.5, 0.0, 0.5)
1161
1162 '''
1163 return Color((h, s, l), 'hsl', alpha, wref)
1164
1165 @staticmethod
1166 def NewFromHsv(h, s, v, alpha=1.0, wref=_DEFAULT_WREF):
1167 '''Create a new instance based on the specifed HSV values.
1168
1169 Parameters:
1170 :h:
1171 The Hus component value [0...1]
1172 :s:
1173 The Saturation component value [0...1]
1174 :v:
1175 The Value component [0...1]
1176 :alpha:
1177 The color transparency [0...1], default is opaque
1178 :wref:
1179 The whitepoint reference, default is 2° D65.
1180
1181 Returns:
1182 A grapefruit.Color instance.
1183
1184 >>> Color.NewFromHsv(30, 1, 1)
1185 (1.0, 0.5, 0.0, 1.0)
1186 >>> Color.NewFromHsv(30, 1, 1, 0.5)
1187 (1.0, 0.5, 0.0, 0.5)
1188
1189 '''
1190 h2, s, l = Color.RgbToHsl(*Color.HsvToRgb(h, s, v))
1191 return Color((h, s, l), 'hsl', alpha, wref)
1192
1193 @staticmethod
1194 def NewFromYiq(y, i, q, alpha=1.0, wref=_DEFAULT_WREF):
1195 '''Create a new instance based on the specifed YIQ values.
1196
1197 Parameters:
1198 :y:
1199 The Y component value [0...1]
1200 :i:
1201 The I component value [0...1]
1202 :q:
1203 The Q component value [0...1]
1204 :alpha:
1205 The color transparency [0...1], default is opaque
1206 :wref:
1207 The whitepoint reference, default is 2° D65.
1208
1209 Returns:
1210 A grapefruit.Color instance.
1211
1212 >>> str(Color.NewFromYiq(0.5922, 0.45885,-0.05))
1213 '(0.999902, 0.499955, -6.6905e-005, 1)'
1214 >>> str(Color.NewFromYiq(0.5922, 0.45885,-0.05, 0.5))
1215 '(0.999902, 0.499955, -6.6905e-005, 0.5)'
1216
1217 '''
1218 return Color(Color.YiqToRgb(y, i, q), 'rgb', alpha, wref)
1219
1220 @staticmethod
1221 def NewFromYuv(y, u, v, alpha=1.0, wref=_DEFAULT_WREF):
1222 '''Create a new instance based on the specifed YUV values.
1223
1224 Parameters:
1225 :y:
1226 The Y component value [0...1]
1227 :u:
1228 The U component value [-0.436...0.436]
1229 :v:
1230 The V component value [-0.615...0.615]
1231 :alpha:
1232 The color transparency [0...1], default is opaque
1233 :wref:
1234 The whitepoint reference, default is 2° D65.
1235
1236 Returns:
1237 A grapefruit.Color instance.
1238
1239 >>> str(Color.NewFromYuv(0.5925, -0.2916, 0.3575))
1240 '(0.999989, 0.500015, -6.3276e-005, 1)'
1241 >>> str(Color.NewFromYuv(0.5925, -0.2916, 0.3575, 0.5))
1242 '(0.999989, 0.500015, -6.3276e-005, 0.5)'
1243
1244 '''
1245 return Color(Color.YuvToRgb(y, u, v), 'rgb', alpha, wref)
1246
1247 @staticmethod
1248 def NewFromXyz(x, y, z, alpha=1.0, wref=_DEFAULT_WREF):
1249 '''Create a new instance based on the specifed CIE-XYZ values.
1250
1251 Parameters:
1252 :x:
1253 The Red component value [0...1]
1254 :y:
1255 The Green component value [0...1]
1256 :z:
1257 The Blue component value [0...1]
1258 :alpha:
1259 The color transparency [0...1], default is opaque
1260 :wref:
1261 The whitepoint reference, default is 2° D65.
1262
1263 Returns:
1264 A grapefruit.Color instance.
1265
1266 >>> str(Color.NewFromXyz(0.488941, 0.365682, 0.0448137))
1267 '(1, 0.5, 6.81883e-008, 1)'
1268 >>> str(Color.NewFromXyz(0.488941, 0.365682, 0.0448137, 0.5))
1269 '(1, 0.5, 6.81883e-008, 0.5)'
1270
1271 '''
1272 return Color(Color.XyzToRgb(x, y, z), 'rgb', alpha, wref)
1273
1274 @staticmethod
1275 def NewFromLab(l, a, b, alpha=1.0, wref=_DEFAULT_WREF):
1276 '''Create a new instance based on the specifed CIE-LAB values.
1277
1278 Parameters:
1279 :l:
1280 The L component [0...100]
1281 :a:
1282 The a component [-1...1]
1283 :b:
1284 The a component [-1...1]
1285 :alpha:
1286 The color transparency [0...1], default is opaque
1287 :wref:
1288 The whitepoint reference, default is 2° D65.
1289
1290 Returns:
1291 A grapefruit.Color instance.
1292
1293 >>> str(Color.NewFromLab(66.9518, 0.43084, 0.739692))
1294 '(1, 0.5, 1.09491e-008, 1)'
1295 >>> str(Color.NewFromLab(66.9518, 0.43084, 0.739692, wref=Color.WHITE_REFERENCE['std_D50']))
1296 '(1.01238, 0.492011, -0.14311, 1)'
1297 >>> str(Color.NewFromLab(66.9518, 0.43084, 0.739692, 0.5))
1298 '(1, 0.5, 1.09491e-008, 0.5)'
1299 >>> str(Color.NewFromLab(66.9518, 0.43084, 0.739692, 0.5, Color.WHITE_REFERENCE['std_D50']))
1300 '(1.01238, 0.492011, -0.14311, 0.5)'
1301
1302 '''
1303 return Color(Color.XyzToRgb(*Color.LabToXyz(l, a, b, wref)), 'rgb', alpha, wref)
1304
1305 @staticmethod
1306 def NewFromCmy(c, m, y, alpha=1.0, wref=_DEFAULT_WREF):
1307 '''Create a new instance based on the specifed CMY values.
1308
1309 Parameters:
1310 :c:
1311 The Cyan component value [0...1]
1312 :m:
1313 The Magenta component value [0...1]
1314 :y:
1315 The Yellow component value [0...1]
1316 :alpha:
1317 The color transparency [0...1], default is opaque
1318 :wref:
1319 The whitepoint reference, default is 2° D65.
1320
1321 Returns:
1322 A grapefruit.Color instance.
1323
1324 >>> Color.NewFromCmy(0, 0.5, 1)
1325 (1, 0.5, 0, 1.0)
1326 >>> Color.NewFromCmy(0, 0.5, 1, 0.5)
1327 (1, 0.5, 0, 0.5)
1328
1329 '''
1330 return Color(Color.CmyToRgb(c, m, y), 'rgb', alpha, wref)
1331
1332 @staticmethod
1333 def NewFromCmyk(c, m, y, k, alpha=1.0, wref=_DEFAULT_WREF):
1334 '''Create a new instance based on the specifed CMYK values.
1335
1336 Parameters:
1337 :c:
1338 The Cyan component value [0...1]
1339 :m:
1340 The Magenta component value [0...1]
1341 :y:
1342 The Yellow component value [0...1]
1343 :k:
1344 The Black component value [0...1]
1345 :alpha:
1346 The color transparency [0...1], default is opaque
1347 :wref:
1348 The whitepoint reference, default is 2° D65.
1349
1350 Returns:
1351 A grapefruit.Color instance.
1352
1353 >>> str(Color.NewFromCmyk(1, 0.32, 0, 0.5))
1354 '(0, 0.34, 0.5, 1)'
1355 >>> str(Color.NewFromCmyk(1, 0.32, 0, 0.5, 0.5))
1356 '(0, 0.34, 0.5, 0.5)'
1357
1358 '''
1359 return Color(Color.CmyToRgb(*Color.CmykToCmy(c, m, y, k)), 'rgb', alpha, wref)
1360
1361 @staticmethod
1362 def NewFromHtml(html, alpha=1.0, wref=_DEFAULT_WREF):
1363 '''Create a new instance based on the specifed HTML color definition.
1364
1365 Parameters:
1366 :html:
1367 The HTML definition of the color (#RRGGBB or #RGB or a color name).
1368 :alpha:
1369 The color transparency [0...1], default is opaque.
1370 :wref:
1371 The whitepoint reference, default is 2° D65.
1372
1373 Returns:
1374 A grapefruit.Color instance.
1375
1376 >>> str(Color.NewFromHtml('#ff8000'))
1377 '(1, 0.501961, 0, 1)'
1378 >>> str(Color.NewFromHtml('ff8000'))
1379 '(1, 0.501961, 0, 1)'
1380 >>> str(Color.NewFromHtml('#f60'))
1381 '(1, 0.4, 0, 1)'
1382 >>> str(Color.NewFromHtml('f60'))
1383 '(1, 0.4, 0, 1)'
1384 >>> str(Color.NewFromHtml('lemonchiffon'))
1385 '(1, 0.980392, 0.803922, 1)'
1386 >>> str(Color.NewFromHtml('#ff8000', 0.5))
1387 '(1, 0.501961, 0, 0.5)'
1388
1389 '''
1390 return Color(Color.HtmlToRgb(html), 'rgb', alpha, wref)
1391
1392 @staticmethod
1393 def NewFromPil(pil, alpha=1.0, wref=_DEFAULT_WREF):
1394 '''Create a new instance based on the specifed PIL color.
1395
1396 Parameters:
1397 :pil:
1398 A PIL compatible color representation (0xBBGGRR)
1399 :alpha:
1400 The color transparency [0...1], default is opaque
1401 :wref:
1402 The whitepoint reference, default is 2° D65.
1403
1404 Returns:
1405 A grapefruit.Color instance.
1406
1407 >>> str(Color.NewFromPil(0x0080ff))
1408 '(1, 0.501961, 0, 1)'
1409 >>> str(Color.NewFromPil(0x0080ff, 0.5))
1410 '(1, 0.501961, 0, 0.5)'
1411
1412 '''
1413 return Color(Color.PilToRgb(pil), 'rgb', alpha, wref)
1414
1415 def __GetAlpha(self):
1416 return self.__a
1417 alpha = property(fget=__GetAlpha, doc='The transparency of this color. 0.0 is transparent and 1.0 is fully opaque.')
1418
1419 def __GetWRef(self):
1420 return self.__wref
1421 whiteRef = property(fget=__GetWRef, doc='the white reference point of this color.')
1422
1423 def __GetRGB(self):
1424 return self.__rgb
1425 rgb = property(fget=__GetRGB, doc='The RGB values of this Color.')
1426
1427 def __GetHue(self):
1428 return self.__hsl[0]
1429 hue = property(fget=__GetHue, doc='The hue of this color.')
1430
1431 def __GetHSL(self):
1432 return self.__hsl
1433 hsl = property(fget=__GetHSL, doc='The HSL values of this Color.')
1434
1435 def __GetHSV(self):
1436 h, s, v = Color.RgbToHsv(*self.__rgb)
1437 return (self.__hsl[0], s, v)
1438 hsv = property(fget=__GetHSV, doc='The HSV values of this Color.')
1439
1440 def __GetYIQ(self):
1441 return Color.RgbToYiq(*self.__rgb)
1442 yiq = property(fget=__GetYIQ, doc='The YIQ values of this Color.')
1443
1444 def __GetYUV(self):
1445 return Color.RgbToYuv(*self.__rgb)
1446 yuv = property(fget=__GetYUV, doc='The YUV values of this Color.')
1447
1448 def __GetXYZ(self):
1449 return Color.RgbToXyz(*self.__rgb)
1450 xyz = property(fget=__GetXYZ, doc='The CIE-XYZ values of this Color.')
1451
1452 def __GetLAB(self):
1453 return Color.XyzToLab(wref=self.__wref, *Color.RgbToXyz(*self.__rgb))
1454 lab = property(fget=__GetLAB, doc='The CIE-LAB values of this Color.')
1455
1456 def __GetCMY(self):
1457 return Color.RgbToCmy(*self.__rgb)
1458 cmy = property(fget=__GetCMY, doc='The CMY values of this Color.')
1459
1460 def __GetCMYK(self):
1461 return Color.CmyToCmyk(*Color.RgbToCmy(*self.__rgb))
1462 cmyk = property(fget=__GetCMYK, doc='The CMYK values of this Color.')
1463
1464 def __GetHTML(self):
1465 return Color.RgbToHtml(*self.__rgb)
1466 html = property(fget=__GetHTML, doc='This Color as an HTML color definition.')
1467
1468 def __GetPIL(self):
1469 return Color.RgbToPil(*self.__rgb)
1470 pil = property(fget=__GetPIL, doc='This Color as a PIL compatible value.')
1471
1472 def __GetwebSafe(self):
1473 return Color.RgbToWebSafe(*self.__rgb)
1474 webSafe = property(fget=__GetwebSafe, doc='The web safe color nearest to this one (RGB).')
1475
1476 def __GetGreyscale(self):
1477 return Color.RgbToGreyscale(*self.rgb)
1478 greyscale = property(fget=__GetGreyscale, doc='The greyscale equivalent to this color (RGB).')
1479
1480 def ColorWithAlpha(self, alpha):
1481 '''Create a new instance based on this one with a new alpha value.
1482
1483 Parameters:
1484 :alpha:
1485 The transparency of the new color [0...1].
1486
1487 Returns:
1488 A grapefruit.Color instance.
1489
1490 >>> Color.NewFromRgb(1.0, 0.5, 0.0, 1.0).ColorWithAlpha(0.5)
1491 (1.0, 0.5, 0.0, 0.5)
1492
1493 '''
1494 return Color(self.__rgb, 'rgb', alpha, self.__wref)
1495
1496 def ColorWithWhiteRef(self, wref, labAsRef=False):
1497 '''Create a new instance based on this one with a new white reference.
1498
1499 Parameters:
1500 :wref:
1501 The whitepoint reference.
1502 :labAsRef:
1503 If True, the L*a*b* values of the current instance are used as reference
1504 for the new color; otherwise, the RGB values are used as reference.
1505
1506 Returns:
1507 A grapefruit.Color instance.
1508
1509
1510 >>> c = Color.NewFromRgb(1.0, 0.5, 0.0, 1.0, Color.WHITE_REFERENCE['std_D65'])
1511
1512 >>> c2 = c.ColorWithWhiteRef(Color.WHITE_REFERENCE['sup_D50'])
1513 >>> c2.rgb
1514 (1.0, 0.5, 0.0)
1515 >>> '(%g, %g, %g)' % c2.whiteRef
1516 '(0.96721, 1, 0.81428)'
1517
1518 >>> c2 = c.ColorWithWhiteRef(Color.WHITE_REFERENCE['sup_D50'], labAsRef=True)
1519 >>> '(%g, %g, %g)' % c2.rgb
1520 '(1.01463, 0.490339, -0.148131)'
1521 >>> '(%g, %g, %g)' % c2.whiteRef
1522 '(0.96721, 1, 0.81428)'
1523 >>> '(%g, %g, %g)' % c.lab
1524 '(66.9518, 0.43084, 0.739692)'
1525 >>> '(%g, %g, %g)' % c2.lab
1526 '(66.9518, 0.43084, 0.739693)'
1527
1528 '''
1529 if labAsRef:
1530 l, a, b = self.__GetLAB()
1531 return Color.NewFromLab(l, a, b, self.__a, wref)
1532 else:
1533 return Color(self.__rgb, 'rgb', self.__a, wref)
1534
1535 def ColorWithHue(self, hue):
1536 '''Create a new instance based on this one with a new hue.
1537
1538 Parameters:
1539 :hue:
1540 The hue of the new color [0...360].
1541
1542 Returns:
1543 A grapefruit.Color instance.
1544
1545 >>> Color.NewFromHsl(30, 1, 0.5).ColorWithHue(60)
1546 (1.0, 1.0, 0.0, 1.0)
1547 >>> Color.NewFromHsl(30, 1, 0.5).ColorWithHue(60).hsl
1548 (60, 1, 0.5)
1549
1550 '''
1551 h, s, l = self.__hsl
1552 return Color((hue, s, l), 'hsl', self.__a, self.__wref)
1553
1554 def ColorWithSaturation(self, saturation):
1555 '''Create a new instance based on this one with a new saturation value.
1556
1557 .. note::
1558
1559 The saturation is defined for the HSL mode.
1560
1561 Parameters:
1562 :saturation:
1563 The saturation of the new color [0...1].
1564
1565 Returns:
1566 A grapefruit.Color instance.
1567
1568 >>> Color.NewFromHsl(30, 1, 0.5).ColorWithSaturation(0.5)
1569 (0.75, 0.5, 0.25, 1.0)
1570 >>> Color.NewFromHsl(30, 1, 0.5).ColorWithSaturation(0.5).hsl
1571 (30, 0.5, 0.5)
1572
1573 '''
1574 h, s, l = self.__hsl
1575 return Color((h, saturation, l), 'hsl', self.__a, self.__wref)
1576
1577 def ColorWithLightness(self, lightness):
1578 '''Create a new instance based on this one with a new lightness value.
1579
1580 Parameters:
1581 :lightness:
1582 The lightness of the new color [0...1].
1583
1584 Returns:
1585 A grapefruit.Color instance.
1586
1587 >>> Color.NewFromHsl(30, 1, 0.5).ColorWithLightness(0.25)
1588 (0.5, 0.25, 0.0, 1.0)
1589 >>> Color.NewFromHsl(30, 1, 0.5).ColorWithLightness(0.25).hsl
1590 (30, 1, 0.25)
1591
1592 '''
1593 h, s, l = self.__hsl
1594 return Color((h, s, lightness), 'hsl', self.__a, self.__wref)
1595
1596 def DarkerColor(self, level):
1597 '''Create a new instance based on this one but darker.
1598
1599 Parameters:
1600 :level:
1601 The amount by which the color should be darkened to produce
1602 the new one [0...1].
1603
1604 Returns:
1605 A grapefruit.Color instance.
1606
1607 >>> Color.NewFromHsl(30, 1, 0.5).DarkerColor(0.25)
1608 (0.5, 0.25, 0.0, 1.0)
1609 >>> Color.NewFromHsl(30, 1, 0.5).DarkerColor(0.25).hsl
1610 (30, 1, 0.25)
1611
1612 '''
1613 h, s, l = self.__hsl
1614 return Color((h, s, max(l - level, 0)), 'hsl', self.__a, self.__wref)
1615
1616 def LighterColor(self, level):
1617 '''Create a new instance based on this one but lighter.
1618
1619 Parameters:
1620 :level:
1621 The amount by which the color should be lightened to produce
1622 the new one [0...1].
1623
1624 Returns:
1625 A grapefruit.Color instance.
1626
1627 >>> Color.NewFromHsl(30, 1, 0.5).LighterColor(0.25)
1628 (1.0, 0.75, 0.5, 1.0)
1629 >>> Color.NewFromHsl(30, 1, 0.5).LighterColor(0.25).hsl
1630 (30, 1, 0.75)
1631
1632 '''
1633 h, s, l = self.__hsl
1634 return Color((h, s, min(l + level, 1)), 'hsl', self.__a, self.__wref)
1635
1636 def Saturate(self, level):
1637 '''Create a new instance based on this one but more saturated.
1638
1639 Parameters:
1640 :level:
1641 The amount by which the color should be saturated to produce
1642 the new one [0...1].
1643
1644 Returns:
1645 A grapefruit.Color instance.
1646
1647 >>> Color.NewFromHsl(30, 0.5, 0.5).Saturate(0.25)
1648 (0.875, 0.5, 0.125, 1.0)
1649 >>> Color.NewFromHsl(30, 0.5, 0.5).Saturate(0.25).hsl
1650 (30, 0.75, 0.5)
1651
1652 '''
1653 h, s, l = self.__hsl
1654 return Color((h, min(s + level, 1), l), 'hsl', self.__a, self.__wref)
1655
1656 def Desaturate(self, level):
1657 '''Create a new instance based on this one but less saturated.
1658
1659 Parameters:
1660 :level:
1661 The amount by which the color should be desaturated to produce
1662 the new one [0...1].
1663
1664 Returns:
1665 A grapefruit.Color instance.
1666
1667 >>> Color.NewFromHsl(30, 0.5, 0.5).Desaturate(0.25)
1668 (0.625, 0.5, 0.375, 1.0)
1669 >>> Color.NewFromHsl(30, 0.5, 0.5).Desaturate(0.25).hsl
1670 (30, 0.25, 0.5)
1671
1672 '''
1673 h, s, l = self.__hsl
1674 return Color((h, max(s - level, 0), l), 'hsl', self.__a, self.__wref)
1675
1676 def WebSafeDither(self):
1677 '''Return the two websafe colors nearest to this one.
1678
1679 Returns:
1680 A tuple of two grapefruit.Color instances which are the two
1681 web safe colors closest this one.
1682
1683 >>> c = Color.NewFromRgb(1.0, 0.45, 0.0)
1684 >>> c1, c2 = c.WebSafeDither()
1685 >>> str(c1)
1686 '(1, 0.4, 0, 1)'
1687 >>> str(c2)
1688 '(1, 0.6, 0, 1)'
1689
1690 '''
1691 return (
1692 Color(Color.RgbToWebSafe(*self.__rgb), 'rgb', self.__a, self.__wref),
1693 Color(Color.RgbToWebSafe(alt=True, *self.__rgb), 'rgb', self.__a, self.__wref))
1694
1695 def Gradient(self, target, steps=100):
1696 '''Create a list with the gradient colors between this and the other color.
1697
1698 Parameters:
1699 :target:
1700 The grapefruit.Color at the other end of the gradient.
1701 :steps:
1702 The number of gradients steps to create.
1703
1704
1705 Returns:
1706 A list of grapefruit.Color instances.
1707
1708 >>> c1 = Color.NewFromRgb(1.0, 0.0, 0.0, alpha=1)
1709 >>> c2 = Color.NewFromRgb(0.0, 1.0, 0.0, alpha=0)
1710 >>> c1.Gradient(c2, 3)
1711 [(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
1713 '''
1714 gradient = []
1715 rgba1 = self.__rgb + (self.__a,)
1716 rgba2 = target.__rgb + (target.__a,)
1717
1718 steps += 1
1719 for n in xrange(1, steps):
1720 d = 1.0*n/steps
1721 r = (rgba1[0]*(1-d)) + (rgba2[0]*d)
1722 g = (rgba1[1]*(1-d)) + (rgba2[1]*d)
1723 b = (rgba1[2]*(1-d)) + (rgba2[2]*d)
1724 a = (rgba1[3]*(1-d)) + (rgba2[3]*d)
1725
1726 gradient.append(Color((r, g, b), 'rgb', a, self.__wref))
1727
1728 return gradient
1729
1730 def ComplementaryColor(self, mode='ryb'):
1731 '''Create a new instance which is the complementary color of this one.
1732
1733 Parameters:
1734 :mode:
1735 Select which color wheel to use for the generation (ryb/rgb).
1736
1737
1738 Returns:
1739 A grapefruit.Color instance.
1740
1741 >>> Color.NewFromHsl(30, 1, 0.5).ComplementaryColor()
1742 (0.0, 0.5, 1.0, 1.0)
1743 >>> Color.NewFromHsl(30, 1, 0.5).ComplementaryColor().hsl
1744 (210, 1, 0.5)
1745
1746 '''
1747 h, s, l = self.__hsl
1748
1749 if mode == 'ryb': h = Color.RgbToRyb(h)
1750 h = (h+180)%360
1751 if mode == 'ryb': h = Color.RybToRgb(h)
1752
1753 return Color((h, s, l), 'hsl', self.__a, self.__wref)
1754
1755 def MonochromeScheme(self):
1756 '''Return 4 colors in the same hue with varying saturation/lightness.
1757
1758 Returns:
1759 A tuple of 4 grapefruit.Color in the same hue as this one,
1760 with varying saturation/lightness.
1761
1762 >>> c = Color.NewFromHsl(30, 0.5, 0.5)
1763 >>> ['(%g, %g, %g)' % clr.hsl for clr in c.MonochromeScheme()]
1764 ['(30, 0.2, 0.8)', '(30, 0.5, 0.3)', '(30, 0.2, 0.6)', '(30, 0.5, 0.8)']
1765
1766 '''
1767 def _wrap(x, min, thres, plus):
1768 if (x-min) < thres: return x + plus
1769 else: return x-min
1770
1771 h, s, l = self.__hsl
1772
1773 s1 = _wrap(s, 0.3, 0.1, 0.3)
1774 l1 = _wrap(l, 0.5, 0.2, 0.3)
1775
1776 s2 = s
1777 l2 = _wrap(l, 0.2, 0.2, 0.6)
1778
1779 s3 = s1
1780 l3 = max(0.2, l + (1-l)*0.2)
1781
1782 s4 = s
1783 l4 = _wrap(l, 0.5, 0.2, 0.3)
1784
1785 return (
1786 Color((h, s1, l1), 'hsl', self.__a, self.__wref),
1787 Color((h, s2, l2), 'hsl', self.__a, self.__wref),
1788 Color((h, s3, l3), 'hsl', self.__a, self.__wref),
1789 Color((h, s4, l4), 'hsl', self.__a, self.__wref))
1790
1791 def TriadicScheme(self, angle=120, mode='ryb'):
1792 '''Return two colors forming a triad or a split complementary with this one.
1793
1794 Parameters:
1795 :angle:
1796 The angle between the hues of the created colors.
1797 The default value makes a triad.
1798 :mode:
1799 Select which color wheel to use for the generation (ryb/rgb).
1800
1801 Returns:
1802 A tuple of two grapefruit.Color forming a color triad with
1803 this one or a split complementary.
1804
1805 >>> c1 = Color.NewFromHsl(30, 1, 0.5)
1806
1807 >>> c2, c3 = c1.TriadicScheme()
1808 >>> c2.hsl
1809 (150.0, 1, 0.5)
1810 >>> c3.hsl
1811 (270.0, 1, 0.5)
1812
1813 >>> c2, c3 = c1.TriadicScheme(40)
1814 >>> c2.hsl
1815 (190.0, 1, 0.5)
1816 >>> c3.hsl
1817 (230.0, 1, 0.5)
1818
1819 '''
1820 h, s, l = self.__hsl
1821 angle = min(angle, 120) / 2.0
1822
1823 if mode == 'ryb': h = Color.RgbToRyb(h)
1824 h += 180
1825 h1 = (h - angle) % 360
1826 h2 = (h + angle) % 360
1827 if mode == 'ryb':
1828 h1 = Color.RybToRgb(h1)
1829 h2 = Color.RybToRgb(h2)
1830
1831 return (
1832 Color((h1, s, l), 'hsl', self.__a, self.__wref),
1833 Color((h2, s, l), 'hsl', self.__a, self.__wref))
1834
1835 def TetradicScheme(self, angle=30, mode='ryb'):
1836 '''Return three colors froming a tetrad with this one.
1837
1838 Parameters:
1839 :angle:
1840 The angle to substract from the adjacent colors hues [-90...90].
1841 You can use an angle of zero to generate a square tetrad.
1842 :mode:
1843 Select which color wheel to use for the generation (ryb/rgb).
1844
1845 Returns:
1846 A tuple of three grapefruit.Color forming a color tetrad with
1847 this one.
1848
1849 >>> col = Color.NewFromHsl(30, 1, 0.5)
1850 >>> [c.hsl for c in col.TetradicScheme(mode='rgb', angle=30)]
1851 [(90, 1, 0.5), (210, 1, 0.5), (270, 1, 0.5)]
1852
1853 '''
1854 h, s, l = self.__hsl
1855
1856 if mode == 'ryb': h = Color.RgbToRyb(h)
1857 h1 = (h + 90 - angle) % 360
1858 h2 = (h + 180) % 360
1859 h3 = (h + 270 - angle) % 360
1860 if mode == 'ryb':
1861 h1 = Color.RybToRgb(h1)
1862 h2 = Color.RybToRgb(h2)
1863 h3 = Color.RybToRgb(h3)
1864
1865 return (
1866 Color((h1, s, l), 'hsl', self.__a, self.__wref),
1867 Color((h2, s, l), 'hsl', self.__a, self.__wref),
1868 Color((h3, s, l), 'hsl', self.__a, self.__wref))
1869
1870 def AnalogousScheme(self, angle=30, mode='ryb'):
1871 '''Return two colors analogous to this one.
1872
1873 Args:
1874 :angle:
1875 The angle between the hues of the created colors and this one.
1876 :mode:
1877 Select which color wheel to use for the generation (ryb/rgb).
1878
1879 Returns:
1880 A tuple of grapefruit.Colors analogous to this one.
1881
1882 >>> c1 = Color.NewFromHsl(30, 1, 0.5)
1883
1884 >>> c2, c3 = c1.AnalogousScheme()
1885 >>> c2.hsl
1886 (330, 1, 0.5)
1887 >>> c3.hsl
1888 (90, 1, 0.5)
1889
1890 >>> c2, c3 = c1.AnalogousScheme(10)
1891 >>> c2.hsl
1892 (20, 1, 0.5)
1893 >>> c3.hsl
1894 (40, 1, 0.5)
1895
1896 '''
1897 h, s, l = self.__hsl
1898
1899 if mode == 'ryb': h = Color.RgbToRyb(h)
1900 h += 360
1901 h1 = (h - angle) % 360
1902 h2 = (h + angle) % 360
1903 if mode == 'ryb':
1904 h1 = Color.RybToRgb(h1)
1905 h2 = Color.RybToRgb(h2)
1906
1907 return (Color((h1, s, l), 'hsl', self.__a, self.__wref),
1908 Color((h2, s, l), 'hsl', self.__a, self.__wref))
1909
1910 def AlphaBlend(self, other):
1911 '''Alpha-blend this color on the other one.
1912
1913 Args:
1914 :other:
1915 The grapefruit.Color to alpha-blend with this one.
1916
1917 Returns:
1918 A grapefruit.Color instance which is the result of alpha-blending
1919 this color on the other one.
1920
1921 >>> c1 = Color.NewFromRgb(1, 0.5, 0, 0.2)
1922 >>> c2 = Color.NewFromRgb(1, 1, 1, 0.8)
1923 >>> c3 = c1.AlphaBlend(c2)
1924 >>> str(c3)
1925 '(1, 0.875, 0.75, 0.84)'
1926
1927 '''
1928 # get final alpha channel
1929 fa = self.__a + other.__a - (self.__a * other.__a)
1930
1931 # get percentage of source alpha compared to final alpha
1932 if fa==0: sa = 0
1933 else: sa = min(1.0, self.__a/other.__a)
1934
1935 # destination percentage is just the additive inverse
1936 da = 1.0 - sa
1937
1938 sr, sg, sb = [v * sa for v in self.__rgb]
1939 dr, dg, db = [v * da for v in other.__rgb]
1940
1941 return Color((sr+dr, sg+dg, sb+db), 'rgb', fa, self.__wref)
1942
1943 def Blend(self, other, percent=0.5):
1944 '''Blend this color with the other one.
1945
1946 Args:
1947 :other:
1948 the grapefruit.Color to blend with this one.
1949
1950 Returns:
1951 A grapefruit.Color instance which is the result of blending
1952 this color on the other one.
1953
1954 >>> c1 = Color.NewFromRgb(1, 0.5, 0, 0.2)
1955 >>> c2 = Color.NewFromRgb(1, 1, 1, 0.6)
1956 >>> c3 = c1.Blend(c2)
1957 >>> str(c3)
1958 '(1, 0.75, 0.5, 0.4)'
1959
1960 '''
1961 dest = 1.0 - percent
1962 rgb = tuple(((u * percent) + (v * dest) for u, v in zip(self.__rgb, other.__rgb)))
1963 a = (self.__a * percent) + (other.__a * dest)
1964 return Color(rgb, 'rgb', a, self.__wref)
1965
1966 def _test():
1967 import doctest
1968 reload(doctest)
1969 doctest.testmod()
1970
1971 if __name__=='__main__':
1972 _test()
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 [egg_info]
1 tag_build =
2 tag_date = 0
3 tag_svn_revision = 0
4
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 '''GrapeFruit setup and build script.'''
18
19 # $Id: setup.py 24 2008-05-25 16:23:22Z xbasty $
20 __author__ = 'Xavier Basty <xbasty@gmail.com>'
21 __version__ = '0.1a3'
22
23
24 # The base package metadata to be used by both distutils and setuptools
25 METADATA = dict(
26 name = "grapefruit",
27 version = __version__,
28 py_modules = ['grapefruit'],
29 author = 'Xavier Basty',
30 author_email = 'xbasty@gmail.com',
31 description = 'A module to manipulate color information easily.',
32 license = 'Apache License 2.0',
33 url = 'http://code.google.com/p/grapefruit/',
34 download_url = 'http://grapefruit.googlecode.com/files/grapefruit-%s.tar.gz' % \
35 __version__,
36 keywords ='color conversion',
37 )
38
39 # Extra package metadata to be used only if setuptools is installed
40 SETUPTOOLS_METADATA = dict(
41 install_requires = ['setuptools'],
42 include_package_data = True,
43 zip_safe = True,
44 classifiers = [
45 'Development Status :: 3 - Alpha',
46 'Intended Audience :: Developers',
47 'License :: OSI Approved :: Apache Software License',
48 'Topic :: Software Development :: Libraries :: Python Modules',
49 'Topic :: Multimedia :: Graphics',
50 ],
51 test_suite = 'grapefruit_test.suite',
52 )
53
54 def Read(file):
55 return open(file).read()
56
57 def BuildLongDescription():
58 return '\n'.join([Read('README'), Read('CHANGES')])
59
60 def Main():
61 # Build the long_description from the README and CHANGES files
62 METADATA['long_description'] = BuildLongDescription()
63
64 # Use setuptools if available, otherwise fallback and use distutils
65 try:
66 import setuptools
67 METADATA.update(SETUPTOOLS_METADATA)
68 setuptools.setup(**METADATA)
69 except ImportError:
70 import distutils.core
71 distutils.core.setup(**METADATA)
72
73
74 if __name__ == '__main__':
75 Main()