webcolors-1.5/0000755000076700007670000000000012502171014012565 5ustar james00000000000000webcolors-1.5/docs/0000755000076700007670000000000012502171014013515 5ustar james00000000000000webcolors-1.5/docs/colors.rst0000644000076700007670000001657412427605447015607 0ustar james00000000000000.. _colors: An overview of colors on the Web ================================ Colors on the Web are typically specified in `the sRGB color space`_, where each color is made up of a red component, a green component and a blue component. This maps to the red, green and blue components of the pixels on a computer display, and to the three sets of cone cells in the human eye, which respond to (roughly) the wavelengths of light associated with red, green and blue. On the Web, sRGB colors are specified in formats which describe the color as a 24-bit integer, where the first 8 bits provide the red value, the second 8 bits the green value and the final 8 bits the blue value. This gives a total space of 256 * 256 * 256 or 16,777,216 unique colors, though due to differences in display technology not all of these colors may be clearly distinguishable on any given physical display. HTML 4 ------ HTML 4 defined `two ways to specify sRGB colors`_: * The character ``#`` followed by three pairs of hexdecimal digits, specifying values for red, green and blue components in that order; for example, ``#0099cc``. * A set of predefined color names which correspond to specific hexadecimal values; for example, ``blue``. HTML 4 defines sixteen such colors. CSS 1 ----- In `its description of color units`_, CSS 1 added three new ways to specify sRGB colors: * The character ``#`` followed by three hexadecimal digits, which is expanded into three hexadecimal pairs by repeating each digit; thus ``#09c`` is equivalent to ``#0099cc``. * The string ``rgb``, followed by parentheses, between which are three base-10 integers in the range 0..255, which are taken to be the values of the red, green and blue components in that order; for example, ``rgb(0, 153, 204)``. * The same as above, except using percentages instead of numeric values; for example, ``rgb(0%, 60%, 80%)``. CSS 1 also suggested a set of sixteen color names. These names were identical to the set defined in HTML 4, but CSS 1 did not provide definitions of their values and stated that they were taken from "the Windows VGA palette". CSS 2 ----- In its `section on colors`_, CSS 2 allowed the same methods of specifying colors as CSS 1, and defined and provided values for sixteen named colors, identical to the set found in HTML 4. CSS 2 also specified `a list of names of system colors`_. These had no fixed color values, but would take on values from the operating system or other user interface, and allowed elements to be styled using the same colors as the surrounding user interface. These names are deprecated as of CSS 3. The CSS 2.1 revision did not add any new methods of specifying sRGB colors, but did define `one additional named color`_: ``orange``. CSS 3 ----- `The CSS 3 color module`_ adds one new way to specify colors: * A hue-saturation-lightness triplet (HSL), using the construct ``hsl()``. CSS 3 also adds support for variable opacity of colors, by allowing the specification of alpha-channel information through the ``rgba()`` and ``hsla()`` constructs. These are used similarly to the ``rgb()`` and ``hsl()`` constructs, except a fourth value is supplied indicating the level of opacity from ``0.0`` (completely transparent) to ``1.0`` (completely opaque). Though not technically a color, the keyword ``transparent`` is also made available in lieu of a color value, and corresponds to ``rgba(0,0,0,0)``. CSS 3 also defines a new set of 147 color names. This set is taken directly from `the named colors defined for SVG (Scalable Vector Graphics)`_ markup, and is a superset of the named colors defined in CSS 2.1. HTML5 ----- HTML5 exists in two forms: a living document maintained by WHATWG, and a W3C Recommendation. The two HTML5 documents, as of this writing, share a common definition of color values and parsing, and formalize the parsing and serialization of colors according to prior standards and real-world implementations in Web browsers. HTML5 does not introduce any new methods of specifying colors, but does simplify the description of colors and introduce useful terminology. * A set of three 8-bit numbers representing the red, blue and green components of an sRGB color is termed a "simple color". * A seven-character string which begins with the character ``#``, followed by six ASCII hex digits (i.e., ``A-Fa-f0-9``), representing the red, green and blue components of an sRGB color, is a "valid simple color". * A valid simple color expressed with only lowercase ASCII hex digits (i.e., ``a-f0-9``) is a "valid lowercase simple color". HTML5 provides three algorithms related to colors: 1. An algorithm for parsing simple color values, which works on any string that is a valid simple color as defined above. 2. An algorithm for serializing simple color values, which will always produce a valid lowercase simple color. 3. A legacy color-parsing algorithm, which will yield a valid simple color from a variety of inputs, including inputs which are valid simple colors, inputs which are valid for formats from other standards, and certain types of "junk" inputs which were common in real-world documents. The HTML5 legacy parsing algorithm does not support the non-color keyword ``transparent`` from CSS 3 and will produce an error for that input. It also does not recognize the CSS 2 "system color" keywords; it will convert each such keyword to simple color, consistently, but in a way which does not follow CSS 2's definitions of these keywords (which itself was system- and configuration-dependent). The implementations in this module are based on the definitions and algorithms of `the W3C HTML5 Recommendation's section on colors`_. .. _the sRGB color space: http://www.w3.org/Graphics/Color/sRGB .. _two ways to specify sRGB colors: http://www.w3.org/TR/html401/types.html#h-6.5 .. _its description of color units: http://www.w3.org/TR/CSS1/#color-units .. _section on colors: http://www.w3.org/TR/CSS2/syndata.html#color-units .. _a list of names of system colors: http://www.w3.org/TR/CSS2/ui.html#system-colors .. _one additional named color: http://www.w3.org/TR/CSS21/changes.html#q2 .. _The CSS 3 color module: http://www.w3.org/TR/css3-color/ .. _the named colors defined for SVG (Scalable Vector Graphics): http://www.w3.org/TR/SVG11/types.html#ColorKeywords .. _the W3C HTML5 Recommendation's section on colors: http://www.w3.org/TR/html5/infrastructure.html#colors .. _support: What this module supports ------------------------- The ``webcolors`` module supports the following methods of specifying sRGB colors, and conversions between them: * Six-digit hexadecimal. * Three-digit hexadecimal. * Integer ``rgb()`` triplet. * Percentage ``rgb()`` triplet. * Varying selections of predefined color names. The ``webcolors`` module **does not support**: * The CSS 1 named colors, which did not have defined values. * The CSS 2 system colors, which did not have fixed values. * The ``transparent`` keyword, which denotes an effective lack of color. * Opacity/alpha-channel information specified via ``rgba()`` triplets. * Colors specified in the HSL color space, via ``hsl()`` or ``hsla()`` triplets. If you need to convert between sRGB-specified colors and HSL-specified colors, or colors specified via other means, consult `the colorsys module`_ in the Python standard library, which can perform conversions amongst several common color systems. .. _the colorsys module: http://docs.python.org/library/colorsys.html webcolors-1.5/docs/conf.py0000644000076700007670000000116312332137070015022 0ustar james00000000000000import os on_rtd = os.environ.get('READTHEDOCS', None) == 'True' extensions = [] templates_path = ['_templates'] source_suffix = '.rst' master_doc = 'index' project = u'webcolors' copyright = u'2009-2014, James Bennett' version = '1.5' release = '1.5' exclude_trees = ['_build'] pygments_style = 'sphinx' html_static_path = ['_static'] htmlhelp_basename = 'webcolorsdoc' latex_documents = [ ('index', 'webcolors.tex', u'webcolors Documentation', u'James Bennett', 'manual'), ] if not on_rtd: import sphinx_rtd_theme html_theme = 'sphinx_rtd_theme' html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] webcolors-1.5/docs/conformance.rst0000644000076700007670000001403412332145233016550 0ustar james00000000000000.. _conformance: Conformance and testing ======================= Much of the behavior of ``webcolors`` is dictated by the relevant Web standards, which define the acceptable color formats, how to determine valid values for each format and the values corresponding to defined color names. Maintaining correct conversions and conformance to those standards is crucial. The normal test suite --------------------- The normal test suite for ``webcolors`` -- that is, the set of unit tests which will execute using standard Python test runners -- aims for 100% code coverage, but does *not* aim for 100% coverage of possible color value inputs and outputs. Instead, it uses a small number of test values to routinely exercise various functions. The test values used in most test functions are chosen to provide, where applicable, at least one of each of the following types of values: * An endpoint of the acceptable range of values (i.e., ``#ffffff`` and/or ``#000000`` for hexadecimal). * A value beyond the high end of the acceptable range (i.e., greater than 255 in an integer triplet, or greater than 100% for a percentage triplet). * A value beyond the low end of the acceptable range (i.e., less than 0 in an integer triplet, or less than 0% for a percentage triplet). * A "negative zero" value (-0 in an integer triplet, or -0% in a percentage triplet). * An arbitrary value not from an endpoint of the acceptable range (usually ``#000080``, chosen because the author likes navy blue). * A value which corresponds to a named color in CSS 3/SVG but not in earlier standards (usually ``#daa520``, which is ``goldenrod`` in CSS 3/SVG). Since this covers the cases most likely to produce problems, it provides good basic confidence in the correctness of the tested functions. However, the normal test suite cannot guarantee that the color definitions included in ``webcolors`` correspond to those in the relevant standards, and cannot provide guarantees of correct conversions for all possible values. For that, additional tests are required. Those tests are contained in two files in the source distribution, which are not executed during normal test runs: ``tests/definitions.py`` and ``tests/full_colors.py``. Verifying color definitions --------------------------- The ``definitions`` test file verifies that the color definitions in ``webcolors`` are correct. It does this by retrieving the relevant standards documents as HTML, parsing out the color definitions in them, and comparing them to the definitions in ``webcolors``. That consists of: * Parsing out the names and hexadecimal values of the 16 named colors in the HTML 4 standard, and checking that the names and values in :data:`~webcolors.HTML4_NAMES_TO_HEX` match. * Parsing out the names and hexadecimal values of the 17 named colors in the CSS 2.1 standard, and checking that the names and values in :data:`~webcolors.CSS21_NAMES_TO_HEX` match. * Parsing out the names and hexadecimal and integer values of the 147 named colors in the CSS 3 color module (although the color set is taken from SVG, CSS 3 provides both hexadecimal and integer values for them, while the SVG standard provides only integer values), and checking that the names and values in :data:`~webcolors.CSS3_NAMES_TO_HEX` match, and that :func:`~webcolors.name_to_rgb` returns the correct integer values. The ``definitions`` file can be run standalone (i.e., ``python tests/definitions.py``) to execute these tests, but it does require an internet connection (to retrieve the standards documents) and requires `the BeautifulSoup library `_ for HTML parsing. Fully verifying correctness of conversions ------------------------------------------ The ``full_colors`` test file exercises :func:`~webcolors.hex_to_rgb`, :func:`~webcolors.rgb_to_hex`, :func:`~webcolors.rgb_to_rgb_percent` and :func:`~webcolors.rgb_percent_to_rgb` as fully as is practical. For conversions between hexadecimal and integer ``rgb()``, that file generates all 16,777,216 possible color values for each format in order (starting at ``#000000`` and ``(0, 0, 0)`` and incrementing), and verifies that each one converts to the corresponding value in the other format. Thus, it is possible to be confident that ``webcolors`` provides correct conversions between all possible color values in those formats. Testing the correctness of conversion to and from percentage ``rgb()``, however, is more difficult, and a full test is not provided, for two reasons: 1. Because percentage ``rgb()`` values can make use of floating-point values, and because standard floating-point types in most common programming languages (Python included) are inherently imprecise, exact verification is not possible. 2. The only rigorous definition of the format of a percentage value is in CSS 2, `which declares a percentage to be `_ "a ```` immediately followed by '%'". `The CSS 2 definition of a number `_ places no limit on the length past the decimal point, and appears to be declaring any real number as a valid value. As the subset of reals in the range 0.0 to 100.0 is uncountably infinite, testing all legal values is not possible on current hardware in any reasonable amount of time. Since precise correctness and completeness are not achievable, ``webcolors`` instead aims to achieve *consistency* in conversions. Specifically, the ``full_colors`` test generates all 16,777,216 integer ``rgb()`` triplets, and for each such triplet ``t`` verifies that the following assertion holds:: t == rgb_percent_to_rgb(rgb_to_rgb_percent(t)) The ``full_colors`` test has no external dependencies other than Python, and does not require an internet connection. It is written to be run standalone (``python tests/full_colors.py``). However, due to the fact that it must generate all 16,777,216 color values multiple times, and perform checks on each one, it does take some time to run even on fast hardware. webcolors-1.5/docs/contents.rst0000644000076700007670000004273212501443212016115 0ustar james00000000000000.. module:: webcolors .. _contents: Module contents =============== The contents of the ``webcolors`` module fall into four categories: 1. Constants which provide mappings between color names and values. 2. Normalization functions which sanitize input in various formats prior to conversion or output. 3. Conversion functions between each method of specifying colors. 4. Implementations of the color parsing and serialization algorithms in HTML5. See :ref:`the documentation regarding conventions ` for information regarding the types and representation of various color formats in ``webcolors``. All conversion functions which involve color names take an optional argument to determine which specification to draw color names from. See :ref:`the list of specification identifiers ` for a list of valid values. All conversion functions, when faced with identifiably invalid hexadecimal color values, or with a request to name a color which has no name in the requested specification, or with an invalid specification identifier, will raise ``ValueError``. In the documentation below, "Unicode string" means the Unicode string type of the Python version being used; on Python 3 this is ``str`` and on Python 2 it is ``unicode``. See :ref:`the documentation on use of Python string types ` for details. Constants --------- The following constants are available for direct use in mapping from color names to values, although it is strongly recommended to use one of the normalizing conversion functions instead. Mappings from names to hexadecimal values ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. data:: HTML4_NAMES_TO_HEX A dictionary whose keys are the normalized names of the sixteen named HTML 4 colors, and whose values are the normalized hexadecimal values of those colors. .. data:: CSS2_NAMES_TO_HEX An alias for :data:`~webcolors.HTML4_NAMES_TO_HEX`, as CSS 2 defined the same set of colors. .. data:: CSS21_NAMES_TO_HEX A dictionary whose keys are the normalized names of the seventeen named CSS 2.1 colors, and whose values are the normalized hexadecimal values of those colors (sixteen of these are identical to HTML 4 and CSS 2; the seventeenth color is ``orange``, added in CSS 2.1). .. data:: CSS3_NAMES_TO_HEX A dictionary whose keys are the normalized names of the 147 named CSS 3 colors, and whose values are the normalized hexadecimal values of those colors. These colors are also identical to the 147 named colors of SVG. Mappings from hexadecimal values to names ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. data:: HTML4_HEX_TO_NAMES A dictionary whose keys are the normalized hexadecimal values of the sixteen named HTML 4 colors, and whose values are the corresponding normalized names. .. data:: CSS2_HEX_TO_NAMES An alias for :data:`~webcolors.HTML4_HEX_TO_NAMES`. .. data:: CSS21_HEX_TO_NAMES A dictionary whose keys are the normalized hexadecimal values of the seventeen named CSS 2.1 colors, and whose values are the corresponding normalized names. .. data:: CSS3_HEX_TO_NAMES A dictionary whose keys are the normalized hexadecimal values of the 147 names CSS 3 colors, and whose values are the corresponding normalized names. The canonical names of these constants are as listed above, entirely in uppercase. For backwards compatibility with older versions of ``webcolors``, aliases are provided whose names are entirely lowercase (for example, ``html4_names_to_hex``). Normalization functions ----------------------- .. function:: normalize_hex(hex_value) Normalize a hexadecimal color value to a string consisting of the character ``#`` followed by six lowercase hexadecimal digits (what HTML5 terms a "valid lowercase simple color"). If the supplied value cannot be interpreted as a hexadecimal color value, ``ValueError`` is raised. See :ref:`the conventions used by this module ` for information on acceptable formats for hexadecimal values. Examples:: >>> normalize_hex(u'#0099cc') '#0099cc' >>> normalize_hex(u'#0099CC') '#0099cc' >>> normalize_hex(u'#09c') '#0099cc' >>> normalize_hex(u'#09C') '#0099cc' >>> normalize_hex(u'#0099gg') Traceback (most recent call last): ... ValueError: '#0099gg' is not a valid hexadecimal color value. >>> normalize_hex(u'0099cc') Traceback (most recent call last): ... ValueError: '0099cc' is not a valid hexadecimal color value. :param hex_value: The hexadecimal color value to normalize. :type hex_value: ``str`` :rtype: Unicode string .. function:: normalize_integer_triplet(rgb_triplet) Normalize an integer ``rgb()`` triplet so that all values are within the range 0..255. Examples:: >>> normalize_integer_triplet((128, 128, 128)) (128, 128, 128) >>> normalize_integer_triplet((0, 0, 0)) (0, 0, 0) >>> normalize_integer_triplet((255, 255, 255)) (255, 255, 255) >>> normalize_integer_triplet((270, -20, -0)) (255, 0, 0) :param rgb_triplet: The integer ``rgb()`` triplet to normalize. :type rgb_triplet: 3-tuple of ``int`` :rtype: 3-tuple of ``int`` .. function:: normalize_percent_triplet(rgb_triplet) Normalize a percentage ``rgb()`` triplet to that all values are within the range 0%..100%. Examples:: >>> normalize_percent_triplet((u'50%', u'50%', u'50%')) (u'50%', u'50%', u'50%') >>> normalize_percent_triplet((u'0%', u'100%', u'0%')) (u'0%', u'100%', u'0%') >>> normalize_percent_triplet((u'-10%', u'-0%', u'500%')) (u'0%', u'0%', u'100%') :param rgb_triplet: The percentage ``rgb()`` triplet to normalize. :type rgb_triplet: 3-tuple of ``str`` :rtype: 3-tuple of Unicode string Conversions from color names to other formats --------------------------------------------- .. function:: name_to_hex(name, spec=u'css3') Convert a color name to a normalized hexadecimal color value. The color name will be normalized to lower-case before being looked up. Examples:: >>> name_to_hex(u'white') u'#ffffff' >>> name_to_hex(u'navy') u'#000080' >>> name_to_hex(u'goldenrod') u'#daa520' >>> name_to_hex(u'goldenrod', spec=u'html4') Traceback (most recent call last): ... ValueError: 'goldenrod' is not defined as a named color in html4. :param name: The color name to convert. :type name: ``str`` :param spec: The specification from which to draw the list of color names; valid values are ``'html4'``, ``'css2'``, ``'css21'`` and ``'css3'``. Default is ``'css3'``. :type spec: ``str`` :rtype: Unicode string .. function:: name_to_rgb(name, spec=u'css3') Convert a color name to a 3-tuple of integers suitable for use in an ``rgb()`` triplet specifying that color. The color name will be normalized to lower-case before being looked up. Examples:: >>> name_to_rgb(u'white') (255, 255, 255) >>> name_to_rgb(u'navy') (0, 0, 128) >>> name_to_rgb(u'goldenrod') (218, 165, 32) :param name: The color name to convert. :type name: ``str`` :param spec: The specification from which to draw the list of color names; valid values are ``'html4'``, ``'css2'``, ``'css21'`` and ``'css3'``. Default is ``'css3'``. :type spec: ``str`` :rtype: 3-tuple of ``int`` .. function:: name_to_rgb_percent(name, spec=u'css3') Convert a color name to a 3-tuple of percentages suitable for use in an ``rgb()`` triplet specifying that color. The color name will be normalized to lower-case before being looked up. Examples:: >>> name_to_rgb_percent(u'white') (u'100%', u'100%', u'100%') >>> name_to_rgb_percent(u'navy') (u'0%', u'0%', u'50%') >>> name_to_rgb_percent(u'goldenrod') (u'85.49%', u'64.71%', u'12.5%') :param name: The color name to convert. :type name: ``str`` :param spec: The specification from which to draw the list of color names; valid values are ``'html4'``, ``'css2'``, ``'css21'`` and ``'css3'``. Default is ``'css3'``. :type spec: ``str`` :rtype: 3-tuple of Unicode string Conversion from hexadecimal color values to other formats ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. function:: hex_to_name(hex_value, spec=u'css3') Convert a hexadecimal color value to its corresponding normalized color name, if any such name exists. The hexadecimal value will be normalized before being looked up. Examples:: >>> hex_to_name(u'#ffffff') u'white' >>> hex_to_name(u'#fff') u'white' >>> hex_to_name(u'#000080') u'navy' >>> hex_to_name(u'#daa520') u'goldenrod' >>> hex_to_name(u'#daa520', spec=u'html4') Traceback (most recent call last): ... ValueError: '#daa520' has no defined color name in html4. :param hex_value: The hexadecimal color value to convert. :type hex_value: str :param spec: The specification from which to draw the list of color names; valid values are ``'html4'``, ``'css2'``, ``'css21'`` and ``'css3'``. Default is ``'css3'``. :type spec: ``str`` :rtype: Unicode string .. function:: hex_to_rgb(hex_value) Convert a hexadecimal color value to a 3-tuple of integers suitable for use in an ``rgb()`` triplet specifying that color. The hexadecimal value will be normalized before being converted. Examples:: >>> hex_to_rgb(u'#fff') (255, 255, 255) >>> hex_to_rgb(u'#000080') (0, 0, 128) :param hex_value: The hexadecimal color value to convert. :type hex_value: ``str`` :rtype: 3-tuple of ``int`` .. function:: hex_to_rgb_percent(hex_value) Convert a hexadecimal color value to a 3-tuple of percentages suitable for use in an ``rgb()`` triplet representing that color. The hexadecimal value will be normalized before being converted. Examples:: >>> hex_to_rgb_percent(u'#ffffff') (u'100%', u'100%', u'100%') >>> hex_to_rgb_percent(u'#000080') (u'0%', u'0%', u'50%') :param hex_value: The hexadecimal color value to convert. :type hex_value: ``str`` :rtype: 3-tuple of Unicode string Conversions from integer ``rgb()`` triplets to other formats ------------------------------------------------------------ .. function:: rgb_to_name(rgb_triplet, spec=u'css3') Convert a 3-tuple of integers, suitable for use in an ``rgb()`` color triplet, to its corresponding normalized color name, if any such name exists. To determine the name, the triplet will be converted to a normalized hexadecimal value. Examples:: >>> rgb_to_name((255, 255, 255)) u'white' >>> rgb_to_name((0, 0, 128)) u'navy' :param rgb_triplet: The ``rgb()`` triplet :type rgb_triplet: 3-tuple of ``int`` :param spec: The specification from which to draw the list of color names; valid values are ``'html4'``, ``'css2'``, ``'css21'`` and ``'css3'``. Default is ``'css3'``. :type spec: ``str`` :rtype: Unicode string .. function:: rgb_to_hex(rgb_triplet) Convert a 3-tuple of integers, suitable for use in an ``rgb()`` color triplet, to a normalized hexadecimal value for that color. Examples:: >>> rgb_to_hex((255, 255, 255)) u'#ffffff' >>> rgb_to_hex((0, 0, 128)) u'#000080' :param rgb_triplet: The ``rgb()`` triplet. :type rgb_triplet: 3-tuple of ``int`` :rtype: Unicode string .. function:: rgb_to_rgb_percent(rgb_triplet) Convert a 3-tuple of integers, suitable for use in an ``rgb()`` color triplet, to a 3-tuple of percentages suitable for use in representing that color. This function makes some trade-offs in terms of the accuracy of the final representation; for some common integer values, special-case logic is used to ensure a precise result (e.g., integer 128 will always convert to '50%', integer 32 will always convert to '12.5%'), but for all other values a standard Python ``float`` is used and rounded to two decimal places, which may result in a loss of precision for some values. Examples:: >>> rgb_to_rgb_percent((255, 255, 255)) (u'100%', u'100%', u'100%') >>> rgb_to_rgb_percent((0, 0, 128)) (u'0%', u'0%', u'50%') >>> rgb_to_rgb_percent((218, 165, 32)) (u'85.49%', u'64.71%', u'12.5%') :param rgb_triplet: The ``rgb()`` triplet. :type rgb_triplet: 3-tuple of ``int`` :rtype: 3-tuple of Unicode string Conversions from percentage ``rgb()`` triplets to other formats --------------------------------------------------------------- .. function:: rgb_percent_to_name(rgb_percent_triplet, spec=u'css3') Convert a 3-tuple of percentages, suitable for use in an ``rgb()`` color triplet, to its corresponding normalized color name, if any such name exists. To determine the name, the triplet will be converted to a normalized hexadecimal value. Examples:: >>> rgb_percent_to_name((u'100%', u'100%', u'100%')) u'white' >>> rgb_percent_to_name((u'0%', u'0%', u'50%')) u'navy' >>> rgb_percent_to_name((u'85.49%', u'64.71%', u'12.5%')) u'goldenrod' :param rgb_percent_triplet: The ``rgb()`` triplet. :type rgb_percent_triplet: 3-tuple of ``str`` :param spec: The specification from which to draw the list of color names; valid values are ``'html4'``, ``'css2'``, ``'css21'`` and ``'css3'``. Default is ``'css3'``. :type spec: ``str`` :rtype: Unicode string .. function:: rgb_percent_to_hex(rgb_percent_triplet) Convert a 3-tuple of percentages, suitable for use in an ``rgb()`` color triplet, to a normalized hexadecimal color value for that color. Examples:: >>> rgb_percent_to_hex((u'100%', u'100%', u'0%')) u'#ffff00' >>> rgb_percent_to_hex((u'0%', u'0%', u'50%')) u'#000080' >>> rgb_percent_to_hex((u'85.49%', u'64.71%', u'12.5%')) u'#daa520' :param rgb_percent_triplet: The ``rgb()`` triplet. :type rgb_percent_triplet: 3-tuple of ``str`` :rtype: ``str`` .. function:: rgb_percent_to_rgb(rgb_percent_triplet) Convert a 3-tuple of percentages, suitable for use in an ``rgb()`` color triplet, to a 3-tuple of integers suitable for use in representing that color. Some precision may be lost in this conversion. See the note regarding precision for :func:`~webcolors.rgb_to_rgb_percent` for details. Examples:: >>> rgb_percent_to_rgb((u'100%', u'100%', u'100%')) (255, 255, 255) >>> rgb_percent_to_rgb((u'0%', u'0%', u'50%')) (0, 0, 128) >>> rgb_percent_to_rgb((u'85.49%', u'64.71%', u'12.5%')) (218, 165, 32) :param rgb_percent_triplet: The ``rgb()`` triplet. :type rgb_percent_triplet: 3-tuple of ``str`` :rtype: 3-tuple of ``int`` HTML5 color algorithms ---------------------- .. warning:: There are two versions of the HTML5 standard. Although they have common origins and are extremely similar, one is a living document (maintained by WHATWG) and the other is a W3C Recommendation. The functions documented below implement the HTML5 color algorithms as given in `section 2.4.6 of the W3C HTML5 Recommendation `_. .. function:: html5_parse_simple_color(input) Apply the HTML5 simple color parsing algorithm. Note that ``input`` *must* be a Unicode string -- on Python 2, bytestrings will not be accepted. Examples:: >>> html5_parse_simple_color(u'#ffffff') (255, 255, 255) >>> html5_parse_simple_color(u'#fff') Traceback (most recent call last): ... ValueError: An HTML5 simple color must be a string exactly seven characters long. :param input: The color to parse. :type input: seven-character ``str`` on Python 3, ``unicode`` on Python 2, which must consist of exactly the character ``#`` followed by six hexadecimal digits :rtype: 3-tuple of ``int``, each in the range 0..255. .. function:: html5_serialize_simple_color(simple_color) Apply the HTML5 simple color serialization algorithm. Examples:: >>> html5_serialize_simple_color((0, 0, 0)) u'#000000' >>> html5_serialize_simple_color((255, 255, 255)) u'#ffffff' :param simple_color: The color to serialize. :type simple_color: 3-tuple of ``int``, each in the range 0..255 :rtype: A valid lowercase simple color, which is a Unicode string exactly seven characters long, beginning with ``#`` and followed by six lowercase hexadecimal digits. .. function:: html5_parse_legacy_color(input) Apply the HTML5 legacy color parsing algorithm. Note that, since this algorithm is intended to handle many types of malformed color values present in real-world Web documents, it is *extremely* forgiving of input, but the results of parsing inputs with high levels of "junk" (i.e., text other than a color value) may be surprising. Note also that ``input`` *must* be a Unicode string -- on Python 2, bytestrings will not be accepted. Examples:: >>> html5_parse_legacy_color(u'black') (0, 0, 0) >>> html5_parse_legacy_color(u'chucknorris') (192, 0, 0) >>> html5_parse_legacy_color(u'Window') (0, 13, 0) :param input: The color to parse. :type input: ``str`` on Python 3, ``unicode`` on Python 2 :rtype: 3-tuple of ``int``, each in the range 0..255webcolors-1.5/docs/conventions.rst0000644000076700007670000001503112501505544016624 0ustar james00000000000000.. _conventions: Normalization and conventions ============================= Since the various formats used to specify colors in Web documents do not always map cleanly to Python data types, and some variation is permitted in how to use each format in a Web document, ``webcolors`` applies a set of conventions for representing color names and values, and for normalizing them. .. _string-types: Python string types ------------------- The ``webcolors`` module is written to be compatible with both Python 2 and Python 3, which have different approaches to strings: * On Python 2, a sequence of bytes in a particular encoding (a "byte string") is represented by the type ``str`` , and Unicode strings are represented by the type ``unicode``. Promiscuous mixing of ``str`` and ``unicode`` is possible in Python 2, but not recommended as it is a frequent source of bugs. * On Python 3, a sequence of bytes in a particular encoding is represented by the type ``bytes``, and Unicode strings are represented by the type ``str``. Promiscuous mixing of ``str`` and ``bytes`` is not permitted in Python 3, and will usually raise exceptions. The approach to string types in ``webcolors`` is as follows: * On Python 3, use of Unicode strings -- ``str`` -- is mandatory for all string arguments to functions in ``webcolors``. Use of ``bytes`` values is forbidden. * All mappings from color names to hexadecimal values (and vice versa) are dictionaries whose keys and values are Unicode strings (``str`` on Python 3 and ``unicode`` on Python 2). This permits promiscuous use of byte strings on Python 2, but ensures that results will be Unicode strings. * All functions whose return values include strings will use Unicode strings (``unicode`` on Python 2 and ``str`` on Python 3). * All functions whose arguments include string values, *except* for the HTML5 color algorithms (see below), will accept a sequence of bytes (``str``) on Python 2, but will convert to Unicode strings (``unicode``) for output. Because the HTML5 Recommendation specifies its color algorithms in terms of Unicode strings only (and in some cases, requires exact identification of Unicode code points to determine behavior), the following constraint applies to the functions implementing these algorithms: * Any string arguments *must* be Unicode strings (``unicode`` on Python 2 or ``str`` on Python 3). Use of ``str`` on Python 2 or ``bytes`` on Python 3 will raise a ``ValueError``. Use of Unicode strings whenever possible is strongly preferred. To encourage this, all documentation for ``webcolors`` uses the ``u`` prefix for string literals. Use of the ``u`` prefix is required on Python 2 to mark a string literal as Unicode; on Pyhon 3.3 and later, use is permitted but not necessary (as all un-prefixed string literals on Python 3 are Unicode strings). Hexadecimal color values ------------------------ For colors specified via hexadecimal values, ``webcolors`` will accept strings in the following formats: * The character ``#`` followed by three hexadecimal digits, where digits A-F may be upper- or lowercase. * The character ``#`` followed by six hexadecimal digits, where digits A-F may be upper- or lowercase (i.e., what HTML5 designates a "valid simple color" when all digits are uppercase, and a "valid lowercase simple color" when all digits are lowercase). For output which consists of a color specified via hexadecimal values, and for functions which perform intermediate conversion to hexadecimal before returning a result in another format, ``webcolors`` always normalizes such values to a string in the following format: * The character ``#`` followed by six hexadecimal digits, with digits A-F forced to lowercase (what HTML5 designates a "valid lowercase simple color"). The function :func:`~webcolors.normalize_hex` can be used to perform this normalization manually if desired. Integer and percentage ``rgb()`` triplets ----------------------------------------- Functions which work with integer ``rgb()`` triplets accept and return them as a 3-tuple of Python ``int``. Functions which work with percentage ``rgb()`` triplets accept them as 3-tuple of Python strings (either ``str`` or ``unicode`` is permitted on Python 2; only ``str`` is permitted on Python 3) and return them as a 3-tuple of Python Unicode strings (``unicode`` or ``str`` depending on Python version). Internally, Python ``float`` is used in some conversions to and from the triplet representations; for each function which may have the precision of its results affected by this, a note is provided in the documentation. For colors specified via ``rgb()`` triplets, values contained in the triplets will be normalized via clipping in accordance with CSS: * Integer values less than 0 will be normalized to 0, and percentage values less than 0% will be normalized to 0%. * Integer values greater than 255 will be normalized to 255, and percentage values greater than 100% will be normalized to 100%. * The "negative zero" values -0 and -0% will be normalized to 0 and 0%, respectively. The functions :func:`~webcolors.normalize_integer_triplet` and :func:`~webcolors.normalize_percent_triplet` can be used to perform this normalization manually if desired. Color names ----------- For colors specified via predefined names, ``webcolors`` will accept strings containing names case-insensitively, so long as they contain no spaces or non-alphabetic characters. Thus, for example, ``u'AliceBlue'`` and ``u'aliceblue'`` are both accepted, and both will refer to the same color (namely, ``rgb(240, 248, 255)``). For output which consists of a color name, and for functions which perform intermediate conversion to a predefined name before returning a result in another format, ``webcolors`` always normalizes such values to be entirely lowercase. .. _spec-identifiers: Identifying sets of named colors ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ For purposes of identifying the specification from which to draw the selection of defined color names, ``webcolors`` recognizes the following strings as identifiers: ``'html4'`` The HTML 4 named colors. ``'css2'`` The CSS 2 named colors. ``'css21'`` The CSS 2.1 named colors. ``'css3'`` The CSS 3/SVG named colors. For all functions for which the set of color names is relevant, this is the default set used. The CSS 1 named colors are not represented here, as CSS 1 merely "suggested" a set of color names, and declined to provide values for them. The CSS 2 "system colors" are also not represented here, as they had no fixed defined values and are now deprecated. webcolors-1.5/docs/faq.rst0000644000076700007670000001110312364747655015044 0ustar james00000000000000.. _faq: Frequently asked questions ========================== The following notes answer common questions, and may be useful to you when using ``webcolors``. What versions of Python are supported? -------------------------------------- On Python 2, ``webcolors`` supports and is tested on Python 2.6 and 2.7. Although ``webcolors`` may work on Python 2.5 or older versions, this is unintentional and unsupported. On Python 3, ``webcolors`` supports and is tested on Python 3.3 and 3.4. Python 3.0, 3.1 and 3.2 are explicitly unsupported, and the ``webcolors`` test suite will not execute on those versions. The minimum-3.3 version requirement is because Python 3.3 was both the first generally-adopted Python 3 release, and because Python 3.3 greatly simplified the process of consistently handling both Python 2 and Python 3 strings in the same codebase. How closely does this module follow the standards? -------------------------------------------------- As closely as is practical (see below regarding floating-point values), within :ref:`the supported formats `; the ``webcolors`` module was written with the relevant standards documents close at hand. See :ref:`the conformance documentation ` for details. Why aren't ``rgb_to_rgb_percent()`` and ``rgb_percent_to_rgb()`` precise? ------------------------------------------------------------------------- This is due to limitations in the representation of floating-point numbers in programming languages. Python, like many programming languages, uses `IEEE floating-point `_, which is inherently imprecise for some values. This imprecision only appears when converting between integer and percentage ``rgb()`` triplets. To work around this, some common values (255, 128, 64, 32, 16 and 0) are handled as special cases, with hard-coded precise results. For all other values, conversion to percentage ``rgb()`` triplet uses a standard Python ``float``, rounding the result to two decimal places. See :ref:`the conformance documentation ` for details on how this affects testing. Why aren't HSL values supported? -------------------------------- In the author's experience, actual use of HSL values on the Web is extremely rare; the overwhelming majority of all colors used on the Web are specified using sRGB, through hexadecimal color values or through integer or percentage ``rgb()`` triplets. This decreases the importance of supporting the ``hsl()`` construct. Additionally, Python already has `the colorsys module`_ in the standard library, which offers functions for converting between RGB, HSL, HSV and YIQ color systems. If you need conversion to/from HSL or another color system, use ``colorsys``. .. _the colorsys module: http://docs.python.org/library/colorsys.html Why not use a more object-oriented design with classes for the colors? ---------------------------------------------------------------------- Representing color values with Python classes would introduce overhead for no real gain. Real-world use cases tend to simply involve working with the actual values, so settling on conventions for how to represent them as Python types, and then offering a function-based interface, accomplishes everything needed without the addtional indirection layer of having to instantiate and serialize a color-wrapping object. Keeping a simple function-based interface also maintains consistency with `Python's built-in colorsys module `_, which has the same style of interface for converting amongst color spaces. Note that if an object-oriented interface is desired, `the third-party colormath module `_ does have a class-based interface (and rightly so, as it offers a wider range of color representation and manipulation options than ``webcolors``). How am I allowed to use this module? ------------------------------------ The ``webcolors`` module is distributed under a `three-clause BSD license `_. This is an open-source license which grants you broad freedom to use, redistribute, modify and distribute modified versions of ``webcolors``. For details, see the file ``LICENSE`` in the source distribution of ``webcolors``. .. _three-clause BSD license: http://opensource.org/licenses/BSD-3-Clause I found a bug or want to make an improvement! --------------------------------------------- The canonical development repository for ``webcolors`` is online at . Issues and pull requests can both be filed there. webcolors-1.5/docs/index.rst0000644000076700007670000000273212502163531015367 0ustar james00000000000000webcolors ========= This module provides utility functions for working with the color names and color value formats defined by the HTML and CSS specifications for use in documents on the Web. Support is included for normalizing and converting between the following formats (RGB colorspace only; conversion to/from HSL can be handled by the ``colorsys`` module in the Python standard library): * Specification-defined color names * Six-digit hexadecimal * Three-digit hexadecimal * Integer ``rgb()`` triplet * Percentage ``rgb()`` triplet For example:: >>> import webcolors >>> webcolors.hex_to_name(u'#daa520') u'goldenrod' Implementations are also provided for the HTML5 color parsing and serialization algorithms. For example, parsing the infamous "chucknorris" string into an rgb() triplet:: >>> import webcolors >>> webcolors.html5_parse_legacy_color(u'chucknorris') (192, 0, 0) Documentation contents ---------------------- .. toctree:: :maxdepth: 1 install colors conventions contents conformance faq .. seealso:: * `The sRGB color space `_ * `HTML 4: Colors `_ * `CSS 1: Color units `_ * `CSS 2: Colors `_ * `CSS 3 color module `_ * `HTML5: Colors `_webcolors-1.5/docs/install.rst0000644000076700007670000000342012501376456015734 0ustar james00000000000000.. _install: Installation guide ================== The ``webcolors`` module has no external dependencies other than Python itself. It's officially tested and supported on the following versions of Python: * Python 2.6 * Python 2.7 * Python 3.3 * Python 3.4 Normal installation ------------------- The preferred method of installing ``webcolors`` is via ``pip``, the standard Python package-installation tool. If you don't have ``pip``, instructions are available for `how to obtain and install it `_. Once you have ``pip``, simply type:: pip install webcolors Manual installation ------------------- It's also possible to install ``webcolors`` manually. To do so, obtain the latest packaged version from `the listing on the Python Package Index `_. Unpack the ``.tar.gz`` file, and run:: python setup.py install Once you've installed ``webcolors``, you can verify successful installation by opening a Python interpreter and typing ``import webcolors``. If the installation was successful, you'll simply get a fresh Python prompt. If you instead see an ``ImportError``, check the configuration of your install tools and your Python import path to ensure ``webcolors`` installed into a location Python can import from. Installing from a source checkout --------------------------------- The development repository for ``webcolors`` is at . Presuming you have `git `_ installed, you can obtain a copy of the repository by typing:: git clone https://github.com/ubernostrum/webcolors.git From there, you can use normal git commands to check out the specific revision you want, and install it using ``python setup.py install``. webcolors-1.5/docs/make.bat0000644000076700007670000000562512214057665015151 0ustar james00000000000000@ECHO OFF REM Command file for Sphinx documentation set SPHINXBUILD=sphinx-build set ALLSPHINXOPTS=-d _build/doctrees %SPHINXOPTS% . if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. changes to make an overview over all changed/added/deprecated items echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (_build\*) do rmdir /q /s %%i del /q /s _build\* goto end ) if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% _build/html echo. echo.Build finished. The HTML pages are in _build/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% _build/dirhtml echo. echo.Build finished. The HTML pages are in _build/dirhtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% _build/pickle echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% _build/json echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% _build/htmlhelp echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in _build/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% _build/qthelp echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in _build/qthelp, like this: echo.^> qcollectiongenerator _build\qthelp\webcolors.qhcp echo.To view the help file: echo.^> assistant -collectionFile _build\qthelp\webcolors.ghc goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% _build/latex echo. echo.Build finished; the LaTeX files are in _build/latex. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% _build/changes echo. echo.The overview file is in _build/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% _build/linkcheck echo. echo.Link check complete; look for any errors in the above output ^ or in _build/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% _build/doctest echo. echo.Testing of doctests in the sources finished, look at the ^ results in _build/doctest/output.txt. goto end ) :end webcolors-1.5/docs/Makefile0000644000076700007670000000566712214057665015212 0ustar james00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d _build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: -rm -rf _build/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) _build/html @echo @echo "Build finished. The HTML pages are in _build/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) _build/dirhtml @echo @echo "Build finished. The HTML pages are in _build/dirhtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) _build/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) _build/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) _build/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in _build/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) _build/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in _build/qthelp, like this:" @echo "# qcollectiongenerator _build/qthelp/webcolors.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile _build/qthelp/webcolors.qhc" latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) _build/latex @echo @echo "Build finished; the LaTeX files are in _build/latex." @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ "run these through (pdf)latex." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) _build/changes @echo @echo "The overview file is in _build/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) _build/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in _build/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) _build/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in _build/doctest/output.txt." webcolors-1.5/LICENSE0000644000076700007670000000276312327544612013617 0ustar james00000000000000Copyright (c) 2008-2014, James Bennett All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the author nor the names of other contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. webcolors-1.5/MANIFEST.in0000644000076700007670000000015112442306163014330 0ustar james00000000000000include LICENSE include MANIFEST.in include README.rst recursive-include docs * recursive-include tests *webcolors-1.5/PKG-INFO0000644000076700007670000000414012502171014013661 0ustar james00000000000000Metadata-Version: 1.1 Name: webcolors Version: 1.5 Summary: A library for working with color names and color value formats defined by the HTML and CSS specifications for use in documents on the Web. Home-page: https://github.com/ubernostrum/webcolors Author: James Bennett Author-email: james@b-list.org License: UNKNOWN Description: .. -*-restructuredtext-*- ``webcolors`` is a simple Python module for working with HTML/CSS color definitions. Support is included for normalizing and converting between the following formats (RGB colorspace only; conversion to/from HSL can be handled by the ``colorsys`` module in the Python standard library): * Specification-defined color names * Six-digit hexadecimal * Three-digit hexadecimal * Integer ``rgb()`` triplet * Percentage ``rgb()`` triplet For example:: >>> import webcolors >>> webcolors.hex_to_name(u'#daa520') u'goldenrod' Implementations are also provided for the HTML5 color parsing and serialization algorithms. For example, parsing the infamous "chucknorris" string into an rgb() triplet:: >>> import webcolors >>> webcolors.html5_parse_legacy_color(u'chucknorris') (192, 0, 0) Full documentation is `available online `_. Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Web Environment Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: BSD License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Topic :: Utilities webcolors-1.5/README.rst0000644000076700007670000000162412502163541014265 0ustar james00000000000000.. -*-restructuredtext-*- ``webcolors`` is a simple Python module for working with HTML/CSS color definitions. Support is included for normalizing and converting between the following formats (RGB colorspace only; conversion to/from HSL can be handled by the ``colorsys`` module in the Python standard library): * Specification-defined color names * Six-digit hexadecimal * Three-digit hexadecimal * Integer ``rgb()`` triplet * Percentage ``rgb()`` triplet For example:: >>> import webcolors >>> webcolors.hex_to_name(u'#daa520') u'goldenrod' Implementations are also provided for the HTML5 color parsing and serialization algorithms. For example, parsing the infamous "chucknorris" string into an rgb() triplet:: >>> import webcolors >>> webcolors.html5_parse_legacy_color(u'chucknorris') (192, 0, 0) Full documentation is `available online `_.webcolors-1.5/setup.py0000644000076700007670000000233612442305773014321 0ustar james00000000000000import os from distutils.core import setup setup(name='webcolors', version='1.5', description='A library for working with color names and color value formats defined by the HTML and CSS specifications for use in documents on the Web.', long_description=open(os.path.join(os.path.dirname(__file__), 'README.rst')).read(), author='James Bennett', author_email='james@b-list.org', url='https://github.com/ubernostrum/webcolors', py_modules=['webcolors'], classifiers=['Development Status :: 5 - Production/Stable', 'Environment :: Web Environment', 'Intended Audience :: Developers', 'License :: OSI Approved :: BSD License', 'Operating System :: OS Independent', 'Programming Language :: Python', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', 'Topic :: Utilities'], ) webcolors-1.5/tests/0000755000076700007670000000000012502171014013727 5ustar james00000000000000webcolors-1.5/tests/__init__.py0000644000076700007670000000000012331140746016036 0ustar james00000000000000webcolors-1.5/tests/definitions.py0000644000076700007670000001040012455160367016627 0ustar james00000000000000""" Test accuracy of the mappings of color names and values, by extracting the definitions of the colors from the relevant standards documents. """ import re import unittest try: import urllib2 except ImportError: import urllib.request as urllib2 from BeautifulSoup import BeautifulSoup import webcolors class HTML4DefinitionTests(unittest.TestCase): """ Extract the names and values of the 16 defined HTML 4 colors from the online version of the standard, and check them against this module's definitions of them. """ def setUp(self): self.html4_colors = {} soup = BeautifulSoup( urllib2.urlopen('http://www.w3.org/TR/html401/types.html')) color_table = soup.find( 'table', attrs={ 'summary': 'Table of color names and their sRGB values'}) for td in color_table.findAll('td'): if (u'width', u'16') not in td.attrs: color_name, color_value = td.text.split(' = ') self.html4_colors[color_name] = color_value.replace('"', '') def test_color_definitions(self): for color_name, color_value in self.html4_colors.items(): self.assertEqual(color_value.lower(), webcolors.HTML4_NAMES_TO_HEX[color_name.lower()]) class CSS21DefinitionTests(unittest.TestCase): """ Extract the names and values of the 17 defined CSS 2.1 colors from the online version of the standard, and check them against this module's definitions of them. """ def setUp(self): self.color_matching_re = re.compile(r'^([a-z]+)(#[a-fA-F0-9]{6})$') self.css21_colors = {} soup = BeautifulSoup( urllib2.urlopen('http://www.w3.org/TR/CSS2/syndata.html')) color_table = soup.find('div', attrs={'id': 'TanteksColorDiagram20020613'}) for color_square in color_table.findAll('span', attrs={ 'class': 'colorsquare'}): color_name, color_value = self.color_matching_re.match( color_square.text ).groups() self.css21_colors[color_name] = color_value def test_color_definitions(self): for color_name, color_value in self.css21_colors.items(): self.assertEqual(color_value.lower(), webcolors.CSS21_NAMES_TO_HEX[color_name.lower()]) class CSS3DefinitionTests(unittest.TestCase): """ Extract the names and values of the 147 defined CSS 3 colors from the online version of the standard, and check them against this module's definitions of them. """ def setUp(self): self.css3_colors = {} soup = BeautifulSoup(urllib2.urlopen( 'http://www.w3.org/TR/css3-color/')) color_table = soup.findAll('table', attrs={'class': 'colortable'})[1] color_names = [dfn.text for dfn in color_table.findAll('dfn')] hex_values = [td.text for td in color_table.findAll('td', attrs={'class': 'c', 'style': 'background:silver'}) if td.text.startswith('#')] rgb_values = [td.text for td in color_table.findAll('td', attrs={'class': 'c', 'style': 'background:silver'}) if not td.text.startswith('#') and not td.text.startswith('&')] for i, color_name in enumerate(color_names): self.css3_colors[color_name] = { 'hex': hex_values[i], 'rgb': tuple(map(int, rgb_values[i].split(',')))} def test_color_definitions(self): for color_name, color_values in self.css3_colors.items(): self.assertEqual(color_values['hex'].lower(), webcolors.CSS3_NAMES_TO_HEX[color_name.lower()]) self.assertEqual(color_values['rgb'], webcolors.name_to_rgb(color_name)) if __name__ == '__main__': unittest.main() webcolors-1.5/tests/full_colors.py0000644000076700007670000000513212501405276016636 0ustar james00000000000000""" Test case which exercises webcolors' conversion functions across all 16,777,216 possible hexadecimal values and all 16,777,216 possible integer rgb() triplet values. You should not ever need to run this test; it is not part of the normal unit-test suite, and is used only as a final check when preparing a new release of webcolors. Because it generates each of the nearly 17 million color values multiple times, this test case takes some time to run and consumes most or all available CPU while running. As a consolation, it is somewhat efficient with respect to memory. Due to the inherent imprecision of floating-point percentage values, and the fact that the legal (with respect to the CSS standards) set of percentage rgb() triplets is uncountably infinite, percentage rgb() triplets are not exhaustively tested here, and the normal test suite is used to ensure correctness of the conversion functions for those values. The only test performed here for percentage rgb() triplets is to ensure that converting an integer rgb() triplet to percentage and back returns the original integer values, for consistency. """ import unittest import webcolors try: # On Python 3, the built-in zip() is identical to the Python 2 # itertools.izip(), and Python 3's itertools does not define an # izip() as a result. from itertools import izip as zip except ImportError: pass try: # Similarly, Python 3's range() does what Python 2's xrange() did, # and so Python 3 does not have xrange() xrange(1) except NameError: xrange = range def hex_colors(): HEX_TEMPLATE = u"#%06x" for i in xrange(16777217): yield HEX_TEMPLATE % i def int_colors(): red_counter = tuple(range(256)) green_counter = tuple(range(256)) blue_counter = tuple(range(256)) for red_value in red_counter: for green_value in green_counter: for blue_value in blue_counter: yield (red_value, green_value, blue_value) class FullColorTest(unittest.TestCase): def test_full_colors(self): for hex_color, int_triplet in zip(hex_colors(), int_colors()): self.assertEqual(int_triplet, webcolors.hex_to_rgb(hex_color)) self.assertEqual(hex_color, webcolors.rgb_to_hex(int_triplet)) def test_triplet_conversion(self): for int_triplet in int_colors(): self.assertEqual(int_triplet, webcolors.rgb_percent_to_rgb( webcolors.rgb_to_rgb_percent(int_triplet))) if __name__ == '__main__': unittest.main() webcolors-1.5/tests/test_conformance.py0000644000076700007670000001631212332402762017645 0ustar james00000000000000""" Conformance tests which do not require an internet connection or HTML parsing libraries, and so can be run as part of the normal test suite of webcolors. For tests which extract the relevant values, during the test run, from the online standards documents (and so require both an internet connection and an HTML parsing library), see the file ``definitions.py`` in this directory. """ import unittest import webcolors # The mappings of color names to values below are used for conformance # testing; while the main webcolors module makes use of alphabetized, # normalized mappings to hex values, the mappings below are the # definitions in precisely the form they take in the relevant # standards documents (they were produced via automated extraction # from the HTML of those documents, to avoid the possibility of human # copy/paste error). # # Sources are: # # HTML 4 colors: http://www.w3.org/TR/html401/types.html#h-6.5 # # SVG colors (which CSS 3 adopted): http://www.w3.org/TR/SVG/types.html#ColorKeywords # # Conformance of this module with the relevant standards is proven by # comparing its output to these mappings. HTML4_COLOR_DEFINITIONS = { 'Black': '#000000', 'Silver': '#C0C0C0', 'Gray': '#808080', 'White': '#FFFFFF', 'Maroon': '#800000', 'Red': '#FF0000', 'Purple': '#800080', 'Fuchsia': '#FF00FF', 'Green': '#008000', 'Lime': '#00FF00', 'Olive': '#808000', 'Yellow': '#FFFF00', 'Navy': '#000080', 'Blue': '#0000FF', 'Teal': '#008080', 'Aqua': '#00FFFF', } SVG_COLOR_DEFINITIONS = { 'aliceblue': (240, 248, 255), 'antiquewhite': (250, 235, 215), 'aqua': (0, 255, 255), 'aquamarine': (127, 255, 212), 'azure': (240, 255, 255), 'beige': (245, 245, 220), 'bisque': (255, 228, 196), 'black': (0, 0, 0), 'blanchedalmond': (255, 235, 205), 'blue': (0, 0, 255), 'blueviolet': (138, 43, 226), 'brown': (165, 42, 42), 'burlywood': (222, 184, 135), 'cadetblue': (95, 158, 160), 'chartreuse': (127, 255, 0), 'chocolate': (210, 105, 30), 'coral': (255, 127, 80), 'cornflowerblue': (100, 149, 237), 'cornsilk': (255, 248, 220), 'crimson': (220, 20, 60), 'cyan': (0, 255, 255), 'darkblue': (0, 0, 139), 'darkcyan': (0, 139, 139), 'darkgoldenrod': (184, 134, 11), 'darkgray': (169, 169, 169), 'darkgreen': (0, 100, 0), 'darkgrey': (169, 169, 169), 'darkkhaki': (189, 183, 107), 'darkmagenta': (139, 0, 139), 'darkolivegreen': (85, 107, 47), 'darkorange': (255, 140, 0), 'darkorchid': (153, 50, 204), 'darkred': (139, 0, 0), 'darksalmon': (233, 150, 122), 'darkseagreen': (143, 188, 143), 'darkslateblue': (72, 61, 139), 'darkslategray': (47, 79, 79), 'darkslategrey': (47, 79, 79), 'darkturquoise': (0, 206, 209), 'darkviolet': (148, 0, 211), 'deeppink': (255, 20, 147), 'deepskyblue': (0, 191, 255), 'dimgray': (105, 105, 105), 'dimgrey': (105, 105, 105), 'dodgerblue': (30, 144, 255), 'firebrick': (178, 34, 34), 'floralwhite': (255, 250, 240), 'forestgreen': (34, 139, 34), 'fuchsia': (255, 0, 255), 'gainsboro': (220, 220, 220), 'ghostwhite': (248, 248, 255), 'gold': (255, 215, 0), 'goldenrod': (218, 165, 32), 'gray': (128, 128, 128), 'grey': (128, 128, 128), 'green': (0, 128, 0), 'greenyellow': (173, 255, 47), 'honeydew': (240, 255, 240), 'hotpink': (255, 105, 180), 'indianred': (205, 92, 92), 'indigo': (75, 0, 130), 'ivory': (255, 255, 240), 'khaki': (240, 230, 140), 'lavender': (230, 230, 250), 'lavenderblush': (255, 240, 245), 'lawngreen': (124, 252, 0), 'lemonchiffon': (255, 250, 205), 'lightblue': (173, 216, 230), 'lightcoral': (240, 128, 128), 'lightcyan': (224, 255, 255), 'lightgoldenrodyellow': (250, 250, 210), 'lightgray': (211, 211, 211), 'lightgreen': (144, 238, 144), 'lightgrey': (211, 211, 211), 'lightpink': (255, 182, 193), 'lightsalmon': (255, 160, 122), 'lightseagreen': (32, 178, 170), 'lightskyblue': (135, 206, 250), 'lightslategray': (119, 136, 153), 'lightslategrey': (119, 136, 153), 'lightsteelblue': (176, 196, 222), 'lightyellow': (255, 255, 224), 'lime': (0, 255, 0), 'limegreen': (50, 205, 50), 'linen': (250, 240, 230), 'magenta': (255, 0, 255), 'maroon': (128, 0, 0), 'mediumaquamarine': (102, 205, 170), 'mediumblue': (0, 0, 205), 'mediumorchid': (186, 85, 211), 'mediumpurple': (147, 112, 219), 'mediumseagreen': (60, 179, 113), 'mediumslateblue': (123, 104, 238), 'mediumspringgreen': (0, 250, 154), 'mediumturquoise': (72, 209, 204), 'mediumvioletred': (199, 21, 133), 'midnightblue': (25, 25, 112), 'mintcream': (245, 255, 250), 'mistyrose': (255, 228, 225), 'moccasin': (255, 228, 181), 'navajowhite': (255, 222, 173), 'navy': (0, 0, 128), 'oldlace': (253, 245, 230), 'olive': (128, 128, 0), 'olivedrab': (107, 142, 35), 'orange': (255, 165, 0), 'orangered': (255, 69, 0), 'orchid': (218, 112, 214), 'palegoldenrod': (238, 232, 170), 'palegreen': (152, 251, 152), 'paleturquoise': (175, 238, 238), 'palevioletred': (219, 112, 147), 'papayawhip': (255, 239, 213), 'peachpuff': (255, 218, 185), 'peru': (205, 133, 63), 'pink': (255, 192, 203), 'plum': (221, 160, 221), 'powderblue': (176, 224, 230), 'purple': (128, 0, 128), 'red': (255, 0, 0), 'rosybrown': (188, 143, 143), 'royalblue': (65, 105, 225), 'saddlebrown': (139, 69, 19), 'salmon': (250, 128, 114), 'sandybrown': (244, 164, 96), 'seagreen': (46, 139, 87), 'seashell': (255, 245, 238), 'sienna': (160, 82, 45), 'silver': (192, 192, 192), 'skyblue': (135, 206, 235), 'slateblue': (106, 90, 205), 'slategray': (112, 128, 144), 'slategrey': (112, 128, 144), 'snow': (255, 250, 250), 'springgreen': (0, 255, 127), 'steelblue': (70, 130, 180), 'tan': (210, 180, 140), 'teal': (0, 128, 128), 'thistle': (216, 191, 216), 'tomato': (255, 99, 71), 'turquoise': (64, 224, 208), 'violet': (238, 130, 238), 'wheat': (245, 222, 179), 'white': (255, 255, 255), 'whitesmoke': (245, 245, 245), 'yellow': (255, 255, 0), 'yellowgreen': (154, 205, 50), } class ConformanceTests(unittest.TestCase): """ Demonstrate that this module conforms to the relevant standards documents governing colors on the Web. """ def test_html_definition_conformance(self): """ Compare the results of name-to-hex conversion to the canonical hex values provided in the HTML 4 specification. """ for color, hex_value in HTML4_COLOR_DEFINITIONS.items(): self.assertEqual(webcolors.normalize_hex(hex_value), webcolors.name_to_hex(color)) def test_svg_definition_conformance(self): """ Compare the results of name-to-rgb-triplet conversion to the canonical triplet values provided in the SVG specification. """ for color, triplet in SVG_COLOR_DEFINITIONS.items(): self.assertEqual(triplet, webcolors.name_to_rgb(color)) webcolors-1.5/tests/test_hexadecimal.py0000644000076700007670000000516612501405530017616 0ustar james00000000000000import unittest import webcolors class HexConversionTests(unittest.TestCase): """ Test functions which convert from hex color codes to other formats. """ def test_hex_to_name(self): """ Test conversion from hex to color name. """ test_pairs = ((u'#ffffff', u'white'), (u'#fff', u'white'), (u'#000080', u'navy'), (u'#daa520', u'goldenrod')) for pair in test_pairs: self.assertEqual(pair[1], webcolors.hex_to_name(pair[0])) def test_hex_to_name_unnamed(self): """ A hex code which does not correspond to a named color, or does not correspond to a named color in the given specification, raises ValueError. """ # No name in any spec. self.assertRaises(ValueError, webcolors.hex_to_name, '#123456') # This is 'goldenrod' in CSS 3 list, unnamed in HTML 4. self.assertRaises(ValueError, webcolors.hex_to_name, '#daa520', spec=u'html4') def test_hex_to_name_specs(self): """ Using one of the supported specifications succeeds; using an unsupported specification raises ValueError. """ for supported_spec in (u'html4', u'css2', u'css21', u'css3'): self.assertEqual(u'white', webcolors.hex_to_name(u'#ffffff', spec=supported_spec)) for unsupported_spec in (u'css1', u'css4', u'html5'): self.assertRaises(ValueError, webcolors.hex_to_name, '#ffffff', spec=unsupported_spec) def test_hex_to_rgb(self): """ Test conversion from hex to integer RGB triplet. """ test_pairs = ((u'#fff', (255, 255, 255)), (u'#ffffff', (255, 255, 255)), (u'#000080', (0, 0, 128))) for pair in test_pairs: self.assertEqual(pair[1], webcolors.hex_to_rgb(pair[0])) def test_hex_to_rgb_percent(self): """ Test conversion from hex to percent RGB triplet. """ test_pairs = ((u'#fff', (u'100%', u'100%', u'100%')), (u'#ffffff', (u'100%', u'100%', u'100%')), (u'#000080', (u'0%', u'0%', u'50%'))) for pair in test_pairs: self.assertEqual(pair[1], webcolors.hex_to_rgb_percent(pair[0])) webcolors-1.5/tests/test_html5.py0000644000076700007670000000701312501405436016401 0ustar james00000000000000import unittest import webcolors class HTML5Tests(unittest.TestCase): """ Test functions which implement the HTML5 color algorithms. """ def test_parse_simple_color(self): """ Test implementation of the HTML5 simple color parsing algorithm. """ test_pairs = ((u'#ffffff', (255, 255, 255)), (u'#000080', (0, 0, 128)), (u'#daa520', (218, 165, 32))) for pair in test_pairs: self.assertEqual(pair[1], webcolors.html5_parse_simple_color(pair[0])) def test_parse_simple_color_error(self): """ Test error conditions of the HTML5 simple color parsing algorithm. """ test_values = (u'0099cc', u'#09c', u'#0000', u'#0000000', u'#0000gg', u'#000000'.encode('ascii')) for value in test_values: self.assertRaises(ValueError, webcolors.html5_parse_simple_color, value) def test_serialize_simple_color(self): """ Test implementation of the HTML5 simple color serialization algorithm. """ test_pairs = (((0, 0, 0), u'#000000'), ((0, 0, 128), u'#000080'), ((218, 165, 32), u'#daa520')) for pair in test_pairs: self.assertEqual(pair[1], webcolors.html5_serialize_simple_color(pair[0])) def test_parse_legacy_color(self): """ Test implementation of the HTML5 legacy color parsing algorithm. """ # One of these is the famous "chucknorris" value. Another is a # CSS 2 system color. The final two are randomly-generated but # believable junk strings. Correct output values obtained # manually. test_pairs = ((u'chucknorris', (192, 0, 0)), (u'Window', (0, 13, 0)), (u'RE|SXLuAse', (224, 0, 224)), (u'+=@FnnWL!Yb}5Dk', (0, 0, 176))) for pair in test_pairs: self.assertEqual(pair[1], webcolors.html5_parse_legacy_color(pair[0])) def test_parse_legacy_color_names(self): """ Test the HTML5 legacy color parsing of SVG/CSS3 color names. """ for name in webcolors.CSS3_NAMES_TO_HEX.keys(): self.assertEqual(webcolors.name_to_rgb(name), webcolors.html5_parse_legacy_color(name)) def test_parse_legacy_color_hex(self): """ Test the HTML5 legacy color parsing of three- and six-digit hexadecimal color values. """ test_values = (u'#000', u'#000000', u'#fff', u'#ffffff', u'#000080') for value in test_values: self.assertEqual(webcolors.hex_to_rgb(value), webcolors.html5_parse_legacy_color(value)) def test_parse_legacy_color_error(self): """ Test error conditions of the HTML5 legacy color parsing algorithm. """ test_values = (u'#000000'.encode('ascii'), u"transparent", u'') for value in test_values: self.assertRaises(ValueError, webcolors.html5_parse_legacy_color, value) webcolors-1.5/tests/test_integer.py0000644000076700007670000000526612501405512017010 0ustar james00000000000000import unittest import webcolors class IntegerRGBConversionTests(unittest.TestCase): """ Test functions which convert from integer RGB triplets to other formats. """ def test_rgb_to_name(self): """ Test conversion from integer RGB triplet to color name. """ test_pairs = (((255, 255, 255), u'white'), ((0, 0, 128), u'navy'), ((218, 165, 32), u'goldenrod')) for pair in test_pairs: self.assertEqual(pair[1], webcolors.rgb_to_name(pair[0])) def test_rgb_to_name_unnamed(self): """ An integer RGB triplet which does not correspond to a named color, or does not correspond to a named color in the given specification, raises ValueError. """ # No name in any spec. self.assertRaises(ValueError, webcolors.rgb_to_name, (18, 52, 86)) # This is 'goldenrod' in CSS 3 list, unnamed in HTML 4. self.assertRaises(ValueError, webcolors.rgb_to_name, (218, 165, 32), spec=u'html4') def test_rgb_to_name_specs(self): """ Using one of the supported specifications succeeds; an unsupported specification raises ValueError. """ for supported_spec in (u'html4', u'css2', u'css21', u'css3'): self.assertEqual(u'white', webcolors.rgb_to_name((255, 255, 255), spec=supported_spec)) for unsupported_spec in (u'css1', u'css4', u'html5'): self.assertRaises(ValueError, webcolors.rgb_to_name, (255, 255, 255), spec=unsupported_spec) def test_rgb_to_hex(self): """ Test conversion from integer RGB triplet to hex. """ test_pairs = (((255, 255, 255), u'#ffffff'), ((0, 0, 128), u'#000080'), ((218, 165, 32), u'#daa520')) for pair in test_pairs: self.assertEqual(pair[1], webcolors.rgb_to_hex(pair[0])) def test_rgb_to_rgb_percent(self): """ Test conversion from integer RGB triplet to percent RGB triplet. """ test_pairs = (((255, 255, 255), (u'100%', u'100%', u'100%')), ((0, 0, 128), (u'0%', u'0%', u'50%')), ((218, 165, 32), (u'85.49%', u'64.71%', u'12.5%'))) for pair in test_pairs: self.assertEqual(pair[1], webcolors.rgb_to_rgb_percent(pair[0])) webcolors-1.5/tests/test_name.py0000644000076700007670000000503212501405620016262 0ustar james00000000000000import unittest import webcolors class NameConversionTests(unittest.TestCase): """ Test functions which convert from color names to other formats. """ def test_name_to_hex(self): """ Test correct conversion of color names to hex. """ test_pairs = ((u'white', u'#ffffff'), (u'navy', u'#000080'), (u'goldenrod', u'#daa520')) for pair in test_pairs: self.assertEqual(pair[1], webcolors.name_to_hex(pair[0])) def test_name_to_hex_bad_name(self): """ A name which does not correspond to a color, or does not correspond to a color in the given specification, raises ValueError. """ test_values = ((u'goldenrod', u'html4'), (u'glue', u'css21'), (u'breen', u'css3')) for value in test_values: self.assertRaises(ValueError, webcolors.name_to_hex, *value) def test_name_to_hex_specs(self): """ Using one of the supported specifications succeeds; using an unsupported specification raises ValueError. """ for supported_spec in (u'html4', u'css2', u'css21', u'css3'): self.assertEqual(u'#ffffff', webcolors.name_to_hex(u'white', spec=supported_spec)) for unsupported_spec in (u'css1', u'css4', u'html5'): self.assertRaises(ValueError, webcolors.name_to_hex, 'white', spec=unsupported_spec) def test_name_to_rgb(self): """ Test conversion from color name to integer RGB triplet. """ test_pairs = ((u'white', (255, 255, 255)), (u'navy', (0, 0, 128)), (u'goldenrod', (218, 165, 32))) for pair in test_pairs: self.assertEqual(pair[1], webcolors.name_to_rgb(pair[0])) def test_name_to_rgb_percent(self): """ Test conversion from color name to percent RGB triplet. """ test_pairs = ((u'white', (u'100%', u'100%', u'100%')), (u'navy', (u'0%', u'0%', u'50%')), (u'goldenrod', (u'85.49%', u'64.71%', u'12.5%'))) for pair in test_pairs: self.assertEqual(pair[1], webcolors.name_to_rgb_percent(pair[0])) webcolors-1.5/tests/test_normalization.py0000644000076700007670000000622712501405672020246 0ustar james00000000000000import unittest import webcolors class NormalizationTests(unittest.TestCase): """ Test both the publicly-exposed and internal normalization functions. """ def test_normalize_hex(self): """ Hexadecimal normalization normalizes valid hex color codes to 6 digits, lowercase. """ test_pairs = ((u'#0099cc', u'#0099cc'), (u'#0099CC', u'#0099cc'), (u'#09c', u'#0099cc'), (u'#09C', u'#0099cc')) for pair in test_pairs: self.assertEqual(pair[1], webcolors.normalize_hex(pair[0])) def test_normalize_hex_format(self): """ Hex normalization raises ValueError on invalid hex color code. """ test_values = (u'0099cc', '#0000gg', '#0000', '#00000000') for value in test_values: self.assertRaises(ValueError, webcolors.normalize_hex, value) def test_normalize_integer_rgb(self): """ Integer normalization clips to 0-255. """ test_pairs = ((255, 255), (0, 0), (128, 128), (-20, 0), (270, 255), (-0, 0)) for pair in test_pairs: self.assertEqual(pair[1], webcolors._normalize_integer_rgb(pair[0])) def test_normalize_integer_triplet(self): """ Integer triplet normalization clips all values to 0-255. """ test_pairs = (((128, 128, 128), (128, 128, 128)), ((0, 0, 0), (0, 0, 0)), ((255, 255, 255), (255, 255, 255)), ((270, -20, 128), (255, 0, 128)), ((-0, -0, -0), (0, 0, 0))) for pair in test_pairs: self.assertEqual(pair[1], webcolors.normalize_integer_triplet(pair[0])) def test_normalize_percent_rgb(self): """ Percent normalization clips to 0%-100%. """ test_pairs = ((u'0%', u'0%'), (u'100%', u'100%'), (u'62%', u'62%'), (u'-5%', u'0%'), (u'250%', u'100%'), (u'85.49%', u'85.49%'), (u'-0%', u'0%')) for pair in test_pairs: self.assertEqual(pair[1], webcolors._normalize_percent_rgb(pair[0])) def test_normalize_percent_triplet(self): """ Percent triplet normalization clips all values to 0%-100%. """ test_pairs = (((u'50%', u'50%', u'50%'), (u'50%', u'50%', u'50%')), ((u'0%', u'100%', u'0%'), (u'0%', u'100%', u'0%')), ((u'-10%', u'250%', u'500%'), (u'0%', u'100%', u'100%')), ((u'-0%', u'-0%', u'-0%'), (u'0%', u'0%', u'0%'))) for pair in test_pairs: self.assertEqual(pair[1], webcolors.normalize_percent_triplet(pair[0])) webcolors-1.5/tests/test_percent.py0000644000076700007670000000567512501405746017030 0ustar james00000000000000import unittest import webcolors class PercentRGBConversionTests(unittest.TestCase): """ Test functions which convert from percent RGB triplets to other formats. """ def test_rgb_percent_to_name(self): """ Test conversion from percent RGB triplet to color name. """ test_pairs = (((u'100%', u'100%', u'100%'), u'white'), ((u'0%', u'0%', u'50%'), u'navy'), ((u'85.49%', u'64.71%', u'12.5%'), u'goldenrod')) for pair in test_pairs: self.assertEqual(pair[1], webcolors.rgb_percent_to_name(pair[0])) def test_rgb_percent_to_name_unnamed(self): """ A percent RGB triplet which does not correspond to a named color, or does not correspond to a named color in the given specification, raises ValueError. """ # No name in any spec. self.assertRaises(ValueError, webcolors.rgb_percent_to_name, (u'7.06%', u'20.39%', u'33.73%')) # This is 'goldenrod' in CSS 3 list, unnamed in HTML 4. self.assertRaises(ValueError, webcolors.rgb_percent_to_name, (u'85.49%', u'64.71%', u'12.5%'), spec=u'html4') def test_rgb_percent_to_name_specs(self): """ Using one of the supported specifications succeeds; an unsupported specification raises ValueError. """ for supported_spec in (u'html4', u'css2', u'css21', u'css3'): self.assertEqual(u'white', webcolors.rgb_percent_to_name( (u'100%', u'100%', u'100%'), spec=supported_spec)) for unsupported_spec in (u'css1', u'css4', u'html5'): self.assertRaises(ValueError, webcolors.rgb_percent_to_name, (u'100%', u'100%', u'100%'), spec=unsupported_spec) def test_rgb_percent_to_hex(self): """ Test conversion from percent RGB triplet to hex. """ test_pairs = (((u'100%', u'100%', u'0%'), u'#ffff00'), ((u'0%', u'0%', u'50%'), u'#000080'), ((u'85.49%', u'64.71%', u'12.5%'), u'#daa520')) for pair in test_pairs: self.assertEqual(pair[1], webcolors.rgb_percent_to_hex(pair[0])) def test_rgb_percent_to_rgb(self): """ Test conversion from percent RGB triplet to integer RGB triplet. """ test_pairs = (((u'100%', u'100%', u'0%'), (255, 255, 0)), ((u'0%', u'0%', u'50%'), (0, 0, 128)), ((u'85.49%', u'64.71%', u'12.5%'), (218, 165, 32))) for pair in test_pairs: self.assertEqual(pair[1], webcolors.rgb_percent_to_rgb(pair[0])) webcolors-1.5/webcolors.py0000644000076700007670000006462712501404154015160 0ustar james00000000000000""" Utility functions for working with the color names and color value formats defined by the HTML and CSS specifications for use in documents on the Web. See documentation (in docs/ directory of source distribution) for details of the supported formats and conversions. """ import math import re import string import struct # Python 2's unichr() is Python 3's chr(). try: unichr except NameError: unichr = chr # Python 2's unicode is Python 3's str. try: unicode except NameError: unicode = str def _reversedict(d): """ Internal helper for generating reverse mappings; given a dictionary, returns a new dictionary with keys and values swapped. """ return dict(zip(d.values(), d.keys())) HEX_COLOR_RE = re.compile(r'^#([a-fA-F0-9]{3}|[a-fA-F0-9]{6})$') SUPPORTED_SPECIFICATIONS = (u'html4', u'css2', u'css21', u'css3') SPECIFICATION_ERROR_TEMPLATE = u"'%%s' is not a supported specification for color name lookups; \ supported specifications are: %s." % (u', '.join(SUPPORTED_SPECIFICATIONS)) # Mappings of color names to normalized hexadecimal color values. ################################################################# # The HTML 4 named colors. # # The canonical source for these color definitions is the HTML 4 # specification: # # http://www.w3.org/TR/html401/types.html#h-6.5 # # The file tests/definitions.py in the source distribution of this # module downloads a copy of the HTML 4 standard and parses out the # color names to ensure the values below are correct. HTML4_NAMES_TO_HEX = { u'aqua': u'#00ffff', u'black': u'#000000', u'blue': u'#0000ff', u'fuchsia': u'#ff00ff', u'green': u'#008000', u'gray': u'#808080', u'lime': u'#00ff00', u'maroon': u'#800000', u'navy': u'#000080', u'olive': u'#808000', u'purple': u'#800080', u'red': u'#ff0000', u'silver': u'#c0c0c0', u'teal': u'#008080', u'white': u'#ffffff', u'yellow': u'#ffff00', } # CSS 2 used the same list as HTML 4. CSS2_NAMES_TO_HEX = HTML4_NAMES_TO_HEX # CSS 2.1 added orange. CSS21_NAMES_TO_HEX = dict(HTML4_NAMES_TO_HEX, orange=u'#ffa500') # The CSS 3/SVG named colors. # # The canonical source for these color definitions is the SVG # specification's color list (which was adopted as CSS 3's color # definition): # # http://www.w3.org/TR/SVG11/types.html#ColorKeywords # # CSS 3 also provides definitions of these colors: # # http://www.w3.org/TR/css3-color/#svg-color # # SVG provides the definitions as RGB triplets. CSS 3 provides them # both as RGB triplets and as hexadecimal. Since hex values are more # common in real-world HTML and CSS, the mapping below is to hex # values instead. The file tests/definitions.py in the source # distribution of this module downloads a copy of the CSS 3 color # module and parses out the color names to ensure the values below are # correct. CSS3_NAMES_TO_HEX = { u'aliceblue': u'#f0f8ff', u'antiquewhite': u'#faebd7', u'aqua': u'#00ffff', u'aquamarine': u'#7fffd4', u'azure': u'#f0ffff', u'beige': u'#f5f5dc', u'bisque': u'#ffe4c4', u'black': u'#000000', u'blanchedalmond': u'#ffebcd', u'blue': u'#0000ff', u'blueviolet': u'#8a2be2', u'brown': u'#a52a2a', u'burlywood': u'#deb887', u'cadetblue': u'#5f9ea0', u'chartreuse': u'#7fff00', u'chocolate': u'#d2691e', u'coral': u'#ff7f50', u'cornflowerblue': u'#6495ed', u'cornsilk': u'#fff8dc', u'crimson': u'#dc143c', u'cyan': u'#00ffff', u'darkblue': u'#00008b', u'darkcyan': u'#008b8b', u'darkgoldenrod': u'#b8860b', u'darkgray': u'#a9a9a9', u'darkgrey': u'#a9a9a9', u'darkgreen': u'#006400', u'darkkhaki': u'#bdb76b', u'darkmagenta': u'#8b008b', u'darkolivegreen': u'#556b2f', u'darkorange': u'#ff8c00', u'darkorchid': u'#9932cc', u'darkred': u'#8b0000', u'darksalmon': u'#e9967a', u'darkseagreen': u'#8fbc8f', u'darkslateblue': u'#483d8b', u'darkslategray': u'#2f4f4f', u'darkslategrey': u'#2f4f4f', u'darkturquoise': u'#00ced1', u'darkviolet': u'#9400d3', u'deeppink': u'#ff1493', u'deepskyblue': u'#00bfff', u'dimgray': u'#696969', u'dimgrey': u'#696969', u'dodgerblue': u'#1e90ff', u'firebrick': u'#b22222', u'floralwhite': u'#fffaf0', u'forestgreen': u'#228b22', u'fuchsia': u'#ff00ff', u'gainsboro': u'#dcdcdc', u'ghostwhite': u'#f8f8ff', u'gold': u'#ffd700', u'goldenrod': u'#daa520', u'gray': u'#808080', u'grey': u'#808080', u'green': u'#008000', u'greenyellow': u'#adff2f', u'honeydew': u'#f0fff0', u'hotpink': u'#ff69b4', u'indianred': u'#cd5c5c', u'indigo': u'#4b0082', u'ivory': u'#fffff0', u'khaki': u'#f0e68c', u'lavender': u'#e6e6fa', u'lavenderblush': u'#fff0f5', u'lawngreen': u'#7cfc00', u'lemonchiffon': u'#fffacd', u'lightblue': u'#add8e6', u'lightcoral': u'#f08080', u'lightcyan': u'#e0ffff', u'lightgoldenrodyellow': u'#fafad2', u'lightgray': u'#d3d3d3', u'lightgrey': u'#d3d3d3', u'lightgreen': u'#90ee90', u'lightpink': u'#ffb6c1', u'lightsalmon': u'#ffa07a', u'lightseagreen': u'#20b2aa', u'lightskyblue': u'#87cefa', u'lightslategray': u'#778899', u'lightslategrey': u'#778899', u'lightsteelblue': u'#b0c4de', u'lightyellow': u'#ffffe0', u'lime': u'#00ff00', u'limegreen': u'#32cd32', u'linen': u'#faf0e6', u'magenta': u'#ff00ff', u'maroon': u'#800000', u'mediumaquamarine': u'#66cdaa', u'mediumblue': u'#0000cd', u'mediumorchid': u'#ba55d3', u'mediumpurple': u'#9370db', u'mediumseagreen': u'#3cb371', u'mediumslateblue': u'#7b68ee', u'mediumspringgreen': u'#00fa9a', u'mediumturquoise': u'#48d1cc', u'mediumvioletred': u'#c71585', u'midnightblue': u'#191970', u'mintcream': u'#f5fffa', u'mistyrose': u'#ffe4e1', u'moccasin': u'#ffe4b5', u'navajowhite': u'#ffdead', u'navy': u'#000080', u'oldlace': u'#fdf5e6', u'olive': u'#808000', u'olivedrab': u'#6b8e23', u'orange': u'#ffa500', u'orangered': u'#ff4500', u'orchid': u'#da70d6', u'palegoldenrod': u'#eee8aa', u'palegreen': u'#98fb98', u'paleturquoise': u'#afeeee', u'palevioletred': u'#db7093', u'papayawhip': u'#ffefd5', u'peachpuff': u'#ffdab9', u'peru': u'#cd853f', u'pink': u'#ffc0cb', u'plum': u'#dda0dd', u'powderblue': u'#b0e0e6', u'purple': u'#800080', u'red': u'#ff0000', u'rosybrown': u'#bc8f8f', u'royalblue': u'#4169e1', u'saddlebrown': u'#8b4513', u'salmon': u'#fa8072', u'sandybrown': u'#f4a460', u'seagreen': u'#2e8b57', u'seashell': u'#fff5ee', u'sienna': u'#a0522d', u'silver': u'#c0c0c0', u'skyblue': u'#87ceeb', u'slateblue': u'#6a5acd', u'slategray': u'#708090', u'slategrey': u'#708090', u'snow': u'#fffafa', u'springgreen': u'#00ff7f', u'steelblue': u'#4682b4', u'tan': u'#d2b48c', u'teal': u'#008080', u'thistle': u'#d8bfd8', u'tomato': u'#ff6347', u'turquoise': u'#40e0d0', u'violet': u'#ee82ee', u'wheat': u'#f5deb3', u'white': u'#ffffff', u'whitesmoke': u'#f5f5f5', u'yellow': u'#ffff00', u'yellowgreen': u'#9acd32', } # Mappings of normalized hexadecimal color values to color names. ################################################################# HTML4_HEX_TO_NAMES = _reversedict(HTML4_NAMES_TO_HEX) CSS2_HEX_TO_NAMES = HTML4_HEX_TO_NAMES CSS21_HEX_TO_NAMES = _reversedict(CSS21_NAMES_TO_HEX) CSS3_HEX_TO_NAMES = _reversedict(CSS3_NAMES_TO_HEX) # Aliases of the above mappings, for backwards compatibility. ################################################################# (html4_names_to_hex, css2_names_to_hex, css21_names_to_hex, css3_names_to_hex) = (HTML4_NAMES_TO_HEX, CSS2_NAMES_TO_HEX, CSS21_NAMES_TO_HEX, CSS3_NAMES_TO_HEX) (html4_hex_to_names, css2_hex_to_names, css21_hex_to_names, css3_hex_to_names) = (HTML4_HEX_TO_NAMES, CSS2_HEX_TO_NAMES, CSS21_HEX_TO_NAMES, CSS3_HEX_TO_NAMES) # Normalization functions. ################################################################# def normalize_hex(hex_value): """ Normalize a hexadecimal color value to 6 digits, lowercase. """ match = HEX_COLOR_RE.match(hex_value) if match is None: raise ValueError( u"'%s' is not a valid hexadecimal color value." % hex_value ) hex_digits = match.group(1) if len(hex_digits) == 3: hex_digits = u''.join(2 * s for s in hex_digits) return u'#%s' % hex_digits.lower() def _normalize_integer_rgb(value): """ Internal normalization function for clipping integer values into the permitted range (0-255, inclusive). """ return 0 if value < 0 \ else 255 if value > 255 \ else value def normalize_integer_triplet(rgb_triplet): """ Normalize an integer ``rgb()`` triplet so that all values are within the range 0-255 inclusive. """ return tuple(_normalize_integer_rgb(value) for value in rgb_triplet) def _normalize_percent_rgb(value): """ Internal normalization function for clipping percent values into the permitted range (0%-100%, inclusive). """ percent = value.split(u'%')[0] percent = float(percent) if u'.' in percent else int(percent) return u'0%' if percent < 0 \ else u'100%' if percent > 100 \ else u'%s%%' % percent def normalize_percent_triplet(rgb_triplet): """ Normalize a percentage ``rgb()`` triplet so that all values are within the range 0%-100% inclusive. """ return tuple(_normalize_percent_rgb(value) for value in rgb_triplet) # Conversions from color names to various formats. ################################################################# def name_to_hex(name, spec=u'css3'): """ Convert a color name to a normalized hexadecimal color value. The optional keyword argument ``spec`` determines which specification's list of color names will be used; valid values are ``html4``, ``css2``, ``css21`` and ``css3``, and the default is ``css3``. When no color of that name exists in the given specification, ``ValueError`` is raised. """ if spec not in SUPPORTED_SPECIFICATIONS: raise ValueError(SPECIFICATION_ERROR_TEMPLATE % spec) normalized = name.lower() hex_value = {u'css2': CSS2_NAMES_TO_HEX, u'css21': CSS21_NAMES_TO_HEX, u'css3': CSS3_NAMES_TO_HEX, u'html4': HTML4_NAMES_TO_HEX}[spec].get(normalized) if hex_value is None: raise ValueError( u"'%s' is not defined as a named color in %s." % (name, spec) ) return hex_value def name_to_rgb(name, spec=u'css3'): """ Convert a color name to a 3-tuple of integers suitable for use in an ``rgb()`` triplet specifying that color. """ return hex_to_rgb(name_to_hex(name, spec=spec)) def name_to_rgb_percent(name, spec=u'css3'): """ Convert a color name to a 3-tuple of percentages suitable for use in an ``rgb()`` triplet specifying that color. """ return rgb_to_rgb_percent(name_to_rgb(name, spec=spec)) # Conversions from hexadecimal color values to various formats. ################################################################# def hex_to_name(hex_value, spec=u'css3'): """ Convert a hexadecimal color value to its corresponding normalized color name, if any such name exists. The optional keyword argument ``spec`` determines which specification's list of color names will be used; valid values are ``html4``, ``css2``, ``css21`` and ``css3``, and the default is ``css3``. When no color name for the value is found in the given specification, ``ValueError`` is raised. """ if spec not in SUPPORTED_SPECIFICATIONS: raise ValueError(SPECIFICATION_ERROR_TEMPLATE % spec) normalized = normalize_hex(hex_value) name = {u'css2': CSS2_HEX_TO_NAMES, u'css21': CSS21_HEX_TO_NAMES, u'css3': CSS3_HEX_TO_NAMES, u'html4': HTML4_HEX_TO_NAMES}[spec].get(normalized) if name is None: raise ValueError( u"'%s' has no defined color name in %s." % (hex_value, spec) ) return name def hex_to_rgb(hex_value): """ Convert a hexadecimal color value to a 3-tuple of integers suitable for use in an ``rgb()`` triplet specifying that color. """ hex_value = normalize_hex(hex_value) hex_value = int(hex_value[1:], 16) return (hex_value >> 16, hex_value >> 8 & 0xff, hex_value & 0xff) def hex_to_rgb_percent(hex_value): """ Convert a hexadecimal color value to a 3-tuple of percentages suitable for use in an ``rgb()`` triplet representing that color. """ return rgb_to_rgb_percent(hex_to_rgb(hex_value)) # Conversions from integer rgb() triplets to various formats. ################################################################# def rgb_to_name(rgb_triplet, spec=u'css3'): """ Convert a 3-tuple of integers, suitable for use in an ``rgb()`` color triplet, to its corresponding normalized color name, if any such name exists. The optional keyword argument ``spec`` determines which specification's list of color names will be used; valid values are ``html4``, ``css2``, ``css21`` and ``css3``, and the default is ``css3``. If there is no matching name, ``ValueError`` is raised. """ return hex_to_name( rgb_to_hex( normalize_integer_triplet(rgb_triplet)), spec=spec) def rgb_to_hex(rgb_triplet): """ Convert a 3-tuple of integers, suitable for use in an ``rgb()`` color triplet, to a normalized hexadecimal value for that color. """ return u'#%02x%02x%02x' % normalize_integer_triplet(rgb_triplet) def rgb_to_rgb_percent(rgb_triplet): """ Convert a 3-tuple of integers, suitable for use in an ``rgb()`` color triplet, to a 3-tuple of percentages suitable for use in representing that color. This function makes some trade-offs in terms of the accuracy of the final representation; for some common integer values, special-case logic is used to ensure a precise result (e.g., integer 128 will always convert to '50%', integer 32 will always convert to '12.5%'), but for all other values a standard Python ``float`` is used and rounded to two decimal places, which may result in a loss of precision for some values. """ # In order to maintain precision for common values, # special-case them. specials = {255: u'100%', 128: u'50%', 64: u'25%', 32: u'12.5%', 16: u'6.25%', 0: u'0%'} return tuple(specials.get(d, u'%.02f%%' % (d / 255.0 * 100)) for d in normalize_integer_triplet(rgb_triplet)) # Conversions from percentage rgb() triplets to various formats. ################################################################# def rgb_percent_to_name(rgb_percent_triplet, spec=u'css3'): """ Convert a 3-tuple of percentages, suitable for use in an ``rgb()`` color triplet, to its corresponding normalized color name, if any such name exists. The optional keyword argument ``spec`` determines which specification's list of color names will be used; valid values are ``html4``, ``css2``, ``css21`` and ``css3``, and the default is ``css3``. If there is no matching name, ``ValueError`` is raised. """ return rgb_to_name( rgb_percent_to_rgb( normalize_percent_triplet( rgb_percent_triplet)), spec=spec) def rgb_percent_to_hex(rgb_percent_triplet): """ Convert a 3-tuple of percentages, suitable for use in an ``rgb()`` color triplet, to a normalized hexadecimal color value for that color. """ return rgb_to_hex( rgb_percent_to_rgb( normalize_percent_triplet(rgb_percent_triplet))) def _percent_to_integer(percent): """ Internal helper for converting a percentage value to an integer between 0 and 255 inclusive. """ num = float(percent.split(u'%')[0]) / 100 * 255 e = num - math.floor(num) return e < 0.5 and int(math.floor(num)) or int(math.ceil(num)) def rgb_percent_to_rgb(rgb_percent_triplet): """ Convert a 3-tuple of percentages, suitable for use in an ``rgb()`` color triplet, to a 3-tuple of integers suitable for use in representing that color. Some precision may be lost in this conversion. See the note regarding precision for ``rgb_to_rgb_percent()`` for details. """ return tuple(map(_percent_to_integer, normalize_percent_triplet(rgb_percent_triplet))) # HTML5 color algorithms. ################################################################# # These functions are written in a way that may seem strange to # developers familiar with Python, because they do not use the most # efficient or idiomatic way of accomplishing their tasks. This is # because, for compliance, these functions are written as literal # translations into Python of the algorithms in HTML5. # # For ease of understanding, the relevant steps of the algorithm from # the standard are included as comments interspersed in the # implementation. def html5_parse_simple_color(input): """ Apply the simple color parsing algorithm from section 2.4.6 of HTML5. """ # 1. Let input be the string being parsed. # # 2. If input is not exactly seven characters long, then return an # error. if not isinstance(input, unicode) or len(input) != 7: raise ValueError( u"An HTML5 simple color must be a Unicode string " u"exactly seven characters long." ) # 3. If the first character in input is not a U+0023 NUMBER SIGN # character (#), then return an error. if not input.startswith('#'): raise ValueError( u"An HTML5 simple color must begin with the " u"character '#' (U+0023)." ) # 4. If the last six characters of input are not all ASCII hex # digits, then return an error. if not all(c in string.hexdigits for c in input[1:]): raise ValueError( u"An HTML5 simple color must contain exactly six ASCII hex digits." ) # 5. Let result be a simple color. # # 6. Interpret the second and third characters as a hexadecimal # number and let the result be the red component of result. # # 7. Interpret the fourth and fifth characters as a hexadecimal # number and let the result be the green component of result. # # 8. Interpret the sixth and seventh characters as a hexadecimal # number and let the result be the blue component of result. # # 9. Return result. result = (int(input[1:3], 16), int(input[3:5], 16), int(input[5:7], 16)) return result def html5_serialize_simple_color(simple_color): """ Apply the serialization algorithm for a simple color from section 2.4.6 of HTML5. """ red, green, blue = simple_color # 1. Let result be a string consisting of a single "#" (U+0023) # character. result = u'#' # 2. Convert the red, green, and blue components in turn to # two-digit hexadecimal numbers using lowercase ASCII hex # digits, zero-padding if necessary, and append these numbers # to result, in the order red, green, blue. result += (u"%02x" % red).lower() result += (u"%02x" % green).lower() result += (u"%02x" % blue).lower() # 3. Return result, which will be a valid lowercase simple color. return result def html5_parse_legacy_color(input): """ Apply the legacy color parsing algorithm from section 2.4.6 of HTML5. """ # 1. Let input be the string being parsed. if not isinstance(input, unicode): raise ValueError( u"HTML5 legacy color parsing requires a Unicode string as input." ) # 2. If input is the empty string, then return an error. if input == "": raise ValueError( u"HTML5 legacy color parsing forbids empty string as a value." ) # 3. Strip leading and trailing whitespace from input. input = input.strip() # 4. If input is an ASCII case-insensitive match for the string # "transparent", then return an error. if input.lower() == u"transparent": raise ValueError( u'HTML5 legacy color parsing forbids "transparent" as a value.' ) # 5. If input is an ASCII case-insensitive match for one of the # keywords listed in the SVG color keywords section of the CSS3 # Color specification, then return the simple color # corresponding to that keyword. keyword_hex = CSS3_NAMES_TO_HEX.get(input.lower()) if keyword_hex is not None: return html5_parse_simple_color(keyword_hex) # 6. If input is four characters long, and the first character in # input is a "#" (U+0023) character, and the last three # characters of input are all ASCII hex digits, then run these # substeps: if len(input) == 4 and \ input.startswith(u'#') and \ all(c in string.hexdigits for c in input[1:]): # 1. Let result be a simple color. # # 2. Interpret the second character of input as a hexadecimal # digit; let the red component of result be the resulting # number multiplied by 17. # # 3. Interpret the third character of input as a hexadecimal # digit; let the green component of result be the resulting # number multiplied by 17. # # 4. Interpret the fourth character of input as a hexadecimal # digit; let the blue component of result be the resulting # number multiplied by 17. result = (int(input[1], 16) * 17, int(input[2], 16) * 17, int(input[3], 16) * 17) # 5. Return result. return result # 7. Replace any characters in input that have a Unicode code # point greater than U+FFFF (i.e. any characters that are not # in the basic multilingual plane) with the two-character # string "00". # This one's a bit weird due to the existence of multiple internal # Unicode string representations in different versions and builds # of Python. # # From Python 2.2 through 3.2, Python could be compiled with # "narrow" or "wide" Unicode strings (see PEP 261). Narrow builds # handled Unicode strings with two-byte characters and surrogate # pairs for non-BMP code points. Wide builds handled Unicode # strings with four-byte characters and no surrogates. This means # ord() is only sufficient to identify a non-BMP character on a # wide build. # # Starting with Python 3.3, the internal string representation # (see PEP 393) is now dynamic, and Python chooses an encoding -- # either latin-1, UCS-2 or UCS-4 -- wide enough to handle the # highest code point in the string. # # The code below bypasses all of that for a consistently effective # method: encode the string to little-endian UTF-32, then perform # a binary unpack of it as four-byte integers. Those integers will # be the Unicode code points, and from there filtering out non-BMP # code points is easy. encoded_input = input.encode('utf_32_le') # Format string is '<' (for little-endian byte order), then a # sequence of 'L' characters (for 4-byte unsigned long integer) # equal to the length of the original string, which is also # one-fourth the encoded length. For example, for a six-character # input the generated format string will be ' 0xffff else unichr(c) for c in codepoints) # 8. If input is longer than 128 characters, truncate input, # leaving only the first 128 characters. if len(input) > 128: input = input[:128] # 9. If the first character in input is a "#" (U+0023) character, # remove it. if input.startswith(u'#'): input = input[1:] # 10. Replace any character in input that is not an ASCII hex # digit with the character "0" (U+0030). if any(c for c in input if c not in string.hexdigits): input = ''.join(c if c in string.hexdigits else u'0' for c in input) # 11. While input's length is zero or not a multiple of three, # append a "0" (U+0030) character to input. while (len(input) == 0) or (len(input) % 3 != 0): input += u'0' # 12. Split input into three strings of equal length, to obtain # three components. Let length be the length of those # components (one third the length of input). length = int(len(input) / 3) red = input[:length] green = input[length:length*2] blue = input[length*2:] # 13. If length is greater than 8, then remove the leading # length-8 characters in each component, and let length be 8. if length > 8: red, green, blue = (red[length-8:], green[length-8:], blue[length-8:]) length = 8 # 14. While length is greater than two and the first character in # each component is a "0" (U+0030) character, remove that # character and reduce length by one. while (length > 2) and (red[0] == u'0' and green[0] == u'0' and blue[0] == u'0'): red, green, blue = (red[1:], green[1:], blue[1:]) length -= 1 # 15. If length is still greater than two, truncate each # component, leaving only the first two characters in each. if length > 2: red, green, blue = (red[:2], green[:2], blue[:2]) # 16. Let result be a simple color. # # 17. Interpret the first component as a hexadecimal number; let # the red component of result be the resulting number. # # 18. Interpret the second component as a hexadecimal number; let # the green component of result be the resulting number. # # 19. Interpret the third component as a hexadecimal number; let # the blue component of result be the resulting number. result = (int(red, 16), int(green, 16), int(blue, 16)) # 20. Return result. return result