File: color.py

package info (click to toggle)
python-weblogo 3.9.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,764 kB
  • sloc: xml: 14,455; python: 11,164; sh: 140; makefile: 67
file content (329 lines) | stat: -rwxr-xr-x 13,192 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
#  Copyright (c) 2005 Gavin E. Crooks
#
#  This software is distributed under the MIT Open Source License.
#  <http://www.opensource.org/licenses/mit-license.html>
#
#  Permission is hereby granted, free of charge, to any person obtaining a
#  copy of this software and associated documentation files (the "Software"),
#  to deal in the Software without restriction, including without limitation
#  the rights to use, copy, modify, merge, publish, distribute, sublicense,
#  and/or sell copies of the Software, and to permit persons to whom the
#  Software is furnished to do so, subject to the following conditions:
#
#  The above copyright notice and this permission notice shall be included
#  in all copies or substantial portions of the Software.
#
#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
#  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
#  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
#  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
#  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
#  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
#  THE SOFTWARE.

"""Color specifications using CSS2 (Cascading Style Sheet) syntax."""

from typing import Any, List


class Color(object):
    """Color specifications using CSS2 (Cascading Style Sheet) syntax.

    http://www.w3.org/TR/REC-CSS2/syndata.html#color-units

    Usage:

    red = Color(255,0,0)
    red = Color(1., 0., 0.)
    red = Color.by_name("red")
    red = Color.from_rgb(1.,0.,0.)
    red = Color.from_rgb(255,0,0)
    red = Color.from_hsl(0.,1., 0.5)

    red = Color.from_string("red")
    red = Color.from_string("RED")
    red = Color.from_string("#F00")
    red = Color.from_string("#FF0000")
    red = Color.from_string("rgb(255, 0, 0)")
    red = Color.from_string("rgb(100%, 0%, 0%)")
    red = Color.from_string("hsl(0, 100%, 50%)")

    """

    def __init__(self, red: float, green: float, blue: float) -> None:
        if not (type(red) is type(green) is type(blue)):
            raise TypeError("Mixed floats and integers?")
        # Convert integer RBG values in [0, 255] to floats in [0, 1]
        if isinstance(red, int):
            red /= 255.0
        if isinstance(green, int):
            green /= 255.0
        if isinstance(blue, int):
            blue /= 255.0
        # Clip RBG values to [0, 1]
        self.red = max(0.0, min(red, 1.0))
        self.green = max(0.0, min(green, 1.0))
        self.blue = max(0.0, min(blue, 1.0))

    @staticmethod
    def names() -> List[str]:
        "Return a list of standard color names."
        return list(_std_colors.keys())

    @classmethod
    def from_rgb(cls, r: float, g: float, b: float) -> "Color":
        return cls(r, g, b)

    @classmethod
    def from_hsl(cls, hue_angle: float, saturation: float, lightness: float) -> "Color":
        def hue_to_rgb(v1: float, v2: float, vH: float) -> float:
            if vH < 0.0:
                vH += 1.0
            if vH > 1.0:
                vH -= 1.0  # pragma: no cover (Grandfathered in)
            if vH * 6.0 < 1.0:
                return v1 + (v2 - v1) * 6.0 * vH
            if vH * 2.0 < 1.0:
                return v2
            if vH * 3.0 < 2.0:
                return v1 + (v2 - v1) * ((2.0 / 3.0) - vH) * 6.0  # pragma: no cover
            return v1

        hue = (((hue_angle % 360.0) + 360.0) % 360.0) / 360.0

        if not (saturation >= 0.0 and saturation <= 1.0):
            raise ValueError(
                "Out-of-range saturation %f" % saturation
            )  # pragma: no cover
        if not (lightness >= 0.0 and lightness <= 1.0):
            raise ValueError(
                "Out-of-range lightness %f" % lightness
            )  # pragma: no cover

        if saturation == 0:
            # greyscale
            return cls.from_rgb(lightness, lightness, lightness)

        if lightness < 0.5:
            v2 = lightness * (1.0 + saturation)
        else:
            v2 = (lightness + saturation) - (saturation * lightness)

        v1 = 2.0 * lightness - v2
        r = hue_to_rgb(v1, v2, hue + (1.0 / 3.0))
        g = hue_to_rgb(v1, v2, hue)
        b = hue_to_rgb(v1, v2, hue - (1.0 / 3.0))

        return cls(r, g, b)

    @staticmethod
    def by_name(string: str) -> "Color":
        s = string.strip().lower().replace(" ", "")
        try:
            return _std_colors[s]
        except KeyError:
            raise ValueError("Unknown color name: %s" % s)

    @classmethod
    def from_string(cls, string: str) -> "Color":
        def to_frac(string: str) -> float:
            # string can be "255" or "100%"
            if string[-1] == "%":
                return float(string[0:-1]) / 100.0
            else:
                return float(string) / 255.0

        s = string.strip().lower().replace(" ", "").replace("_", "")

        if s in _std_colors:  # "red"
            return _std_colors[s]

        if s[0] == "#":  # "#fef"
            if len(s) == 4:
                r = int(s[1] + s[1], 16)
                g = int(s[2] + s[2], 16)
                b = int(s[3] + s[3], 16)
                return cls(r, g, b)
            elif len(s) == 7:  # "#ff00aa"
                r = int(s[1:3], 16)
                g = int(s[3:5], 16)
                b = int(s[5:7], 16)
                return cls(r, g, b)
            else:
                raise ValueError("Cannot parse string: %s" % s)

        if s[0:4] == "rgb(" and s[-1] == ")":
            rgb = s[4:-1].split(",")
            if len(rgb) != 3:
                raise ValueError("Cannot parse string a: %s" % s)
            return cls(to_frac(rgb[0]), to_frac(rgb[1]), to_frac(rgb[2]))

        if s[0:4] == "hsl(" and s[-1] == ")":
            hsl = s[4:-1].split(",")
            if len(hsl) != 3:
                raise ValueError("Cannot parse string a: %s" % s)
            return cls.from_hsl(int(hsl[0]), to_frac(hsl[1]), to_frac(hsl[2]))

        raise ValueError("Cannot parse string: %s" % s)

    def __eq__(self, other: Any) -> bool:
        if not isinstance(other, self.__class__):
            return False
        req = int(0.5 + 255.0 * self.red) == int(0.5 + 255.0 * other.red)
        beq = int(0.5 + 255.0 * self.blue) == int(0.5 + 255.0 * other.blue)
        geq = int(0.5 + 255.0 * self.green) == int(0.5 + 255.0 * other.green)
        return req and beq and geq

    def __repr__(self) -> str:
        return "Color(%f,%f,%f)" % (self.red, self.green, self.blue)


_std_colors = dict(
    aliceblue=Color(240, 248, 255),  # f0f8ff
    antiquewhite=Color(250, 235, 215),  # faebd7
    aqua=Color(0, 255, 255),  # 00ffff
    aquamarine=Color(127, 255, 212),  # 7fffd4
    azure=Color(240, 255, 255),  # f0ffff
    beige=Color(245, 245, 220),  # f5f5dc
    bisque=Color(255, 228, 196),  # ffe4c4
    black=Color(0, 0, 0),  # 000000
    blanchedalmond=Color(255, 235, 205),  # ffebcd
    blue=Color(0, 0, 255),  # 0000ff
    blueviolet=Color(138, 43, 226),  # 8a2be2
    brown=Color(165, 42, 42),  # a52a2a
    burlywood=Color(222, 184, 135),  # deb887
    cadetblue=Color(95, 158, 160),  # 5f9ea0
    chartreuse=Color(127, 255, 0),  # 7fff00
    chocolate=Color(210, 105, 30),  # d2691e
    coral=Color(255, 127, 80),  # ff7f50
    cornflowerblue=Color(100, 149, 237),  # 6495ed
    cornsilk=Color(255, 248, 220),  # fff8dc
    crimson=Color(220, 20, 60),  # dc143c
    cyan=Color(0, 255, 255),  # 00ffff
    darkblue=Color(0, 0, 139),  # 00008b
    darkcyan=Color(0, 139, 139),  # 008b8b
    darkgoldenrod=Color(184, 134, 11),  # b8860b
    darkgray=Color(169, 169, 169),  # a9a9a9
    darkgreen=Color(0, 100, 0),  # 006400
    darkgrey=Color(169, 169, 169),  # a9a9a9
    darkkhaki=Color(189, 183, 107),  # bdb76b
    darkmagenta=Color(139, 0, 139),  # 8b008b
    darkolivegreen=Color(85, 107, 47),  # 556b2f
    darkorange=Color(255, 140, 0),  # ff8c00
    darkorchid=Color(153, 50, 204),  # 9932cc
    darkred=Color(139, 0, 0),  # 8b0000
    darksalmon=Color(233, 150, 122),  # e9967a
    darkseagreen=Color(143, 188, 143),  # 8fbc8f
    darkslateblue=Color(72, 61, 139),  # 483d8b
    darkslategray=Color(47, 79, 79),  # 2f4f4f
    darkslategrey=Color(47, 79, 79),  # 2f4f4f
    darkturquoise=Color(0, 206, 209),  # 00ced1
    darkviolet=Color(148, 0, 211),  # 9400d3
    deeppink=Color(255, 20, 147),  # ff1493
    deepskyblue=Color(0, 191, 255),  # 00bfff
    dimgray=Color(105, 105, 105),  # 696969
    dimgrey=Color(105, 105, 105),  # 696969
    dodgerblue=Color(30, 144, 255),  # 1e90ff
    firebrick=Color(178, 34, 34),  # b22222
    floralwhite=Color(255, 250, 240),  # fffaf0
    forestgreen=Color(34, 139, 34),  # 228b22
    fuchsia=Color(255, 0, 255),  # ff00ff
    gainsboro=Color(220, 220, 220),  # dcdcdc
    ghostwhite=Color(248, 248, 255),  # f8f8ff
    gold=Color(255, 215, 0),  # ffd700
    goldenrod=Color(218, 165, 32),  # daa520
    gray=Color(128, 128, 128),  # 808080
    green=Color(0, 128, 0),  # 008000
    greenyellow=Color(173, 255, 47),  # adff2f
    grey=Color(128, 128, 128),  # 808080
    honeydew=Color(240, 255, 240),  # f0fff0
    hotpink=Color(255, 105, 180),  # ff69b4
    indianred=Color(205, 92, 92),  # cd5c5c
    indigo=Color(75, 0, 130),  # 4b0082
    ivory=Color(255, 255, 240),  # fffff0
    khaki=Color(240, 230, 140),  # f0e68c
    lavender=Color(230, 230, 250),  # e6e6fa
    lavenderblush=Color(255, 240, 245),  # fff0f5
    lawngreen=Color(124, 252, 0),  # 7cfc00
    lemonchiffon=Color(255, 250, 205),  # fffacd
    lightblue=Color(173, 216, 230),  # add8e6
    lightcoral=Color(240, 128, 128),  # f08080
    lightcyan=Color(224, 255, 255),  # e0ffff
    lightgoldenrodyellow=Color(250, 250, 210),  # fafad2
    lightgray=Color(211, 211, 211),  # d3d3d3
    lightgreen=Color(144, 238, 144),  # 90ee90
    lightgrey=Color(211, 211, 211),  # d3d3d3
    lightpink=Color(255, 182, 193),  # ffb6c1
    lightsalmon=Color(255, 160, 122),  # ffa07a
    lightseagreen=Color(32, 178, 170),  # 20b2aa
    lightskyblue=Color(135, 206, 250),  # 87cefa
    lightslategray=Color(119, 136, 153),  # 778899
    lightslategrey=Color(119, 136, 153),  # 778899
    lightsteelblue=Color(176, 196, 222),  # b0c4de
    lightyellow=Color(255, 255, 224),  # ffffe0
    lime=Color(0, 255, 0),  # 00ff00
    limegreen=Color(50, 205, 50),  # 32cd32
    linen=Color(250, 240, 230),  # faf0e6
    magenta=Color(255, 0, 255),  # ff00ff
    maroon=Color(128, 0, 0),  # 800000
    mediumaquamarine=Color(102, 205, 170),  # 66cdaa
    mediumblue=Color(0, 0, 205),  # 0000cd
    mediumorchid=Color(186, 85, 211),  # ba55d3
    mediumpurple=Color(147, 112, 219),  # 9370db
    mediumseagreen=Color(60, 179, 113),  # 3cb371
    mediumslateblue=Color(123, 104, 238),  # 7b68ee
    mediumspringgreen=Color(0, 250, 154),  # 00fa9a
    mediumturquoise=Color(72, 209, 204),  # 48d1cc
    mediumvioletred=Color(199, 21, 133),  # c71585
    midnightblue=Color(25, 25, 112),  # 191970
    mintcream=Color(245, 255, 250),  # f5fffa
    mistyrose=Color(255, 228, 225),  # ffe4e1
    moccasin=Color(255, 228, 181),  # ffe4b5
    navajowhite=Color(255, 222, 173),  # ffdead
    navy=Color(0, 0, 128),  # 000080
    oldlace=Color(253, 245, 230),  # fdf5e6
    olive=Color(128, 128, 0),  # 808000
    olivedrab=Color(107, 142, 35),  # 6b8e23
    orange=Color(255, 165, 0),  # ffa500
    orangered=Color(255, 69, 0),  # ff4500
    orchid=Color(218, 112, 214),  # da70d6
    palegoldenrod=Color(238, 232, 170),  # eee8aa
    palegreen=Color(152, 251, 152),  # 98fb98
    paleturquoise=Color(175, 238, 238),  # afeeee
    palevioletred=Color(219, 112, 147),  # db7093
    papayawhip=Color(255, 239, 213),  # ffefd5
    peachpuff=Color(255, 218, 185),  # ffdab9
    peru=Color(205, 133, 63),  # cd853f
    pink=Color(255, 192, 203),  # ffc0cb
    plum=Color(221, 160, 221),  # dda0dd
    powderblue=Color(176, 224, 230),  # b0e0e6
    purple=Color(128, 0, 128),  # 800080
    red=Color(255, 0, 0),  # ff0000
    rosybrown=Color(188, 143, 143),  # bc8f8f
    royalblue=Color(65, 105, 225),  # 4169e1
    saddlebrown=Color(139, 69, 19),  # 8b4513
    salmon=Color(250, 128, 114),  # fa8072
    sandybrown=Color(244, 164, 96),  # f4a460
    seagreen=Color(46, 139, 87),  # 2e8b57
    seashell=Color(255, 245, 238),  # fff5ee
    sienna=Color(160, 82, 45),  # a0522d
    silver=Color(192, 192, 192),  # c0c0c0
    skyblue=Color(135, 206, 235),  # 87ceeb
    slateblue=Color(106, 90, 205),  # 6a5acd
    slategray=Color(112, 128, 144),  # 708090
    slategrey=Color(112, 128, 144),  # 708090
    snow=Color(255, 250, 250),  # fffafa
    springgreen=Color(0, 255, 127),  # 00ff7f
    steelblue=Color(70, 130, 180),  # 4682b4
    tan=Color(210, 180, 140),  # d2b48c
    teal=Color(0, 128, 128),  # 008080
    thistle=Color(216, 191, 216),  # d8bfd8
    tomato=Color(255, 99, 71),  # ff6347
    turquoise=Color(64, 224, 208),  # 40e0d0
    violet=Color(238, 130, 238),  # ee82ee
    wheat=Color(245, 222, 179),  # f5deb3
    white=Color(255, 255, 255),  # ffffff
    whitesmoke=Color(245, 245, 245),  # f5f5f5
    yellow=Color(255, 255, 0),  # ffff00
    yellowgreen=Color(154, 205, 50),  # 9acd32
)