Coverage for /usr/lib/python3/dist-packages/PIL/ImageColor.py: 14%
64 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
1#
2# The Python Imaging Library
3# $Id$
4#
5# map CSS3-style colour description strings to RGB
6#
7# History:
8# 2002-10-24 fl Added support for CSS-style color strings
9# 2002-12-15 fl Added RGBA support
10# 2004-03-27 fl Fixed remaining int() problems for Python 1.5.2
11# 2004-07-19 fl Fixed gray/grey spelling issues
12# 2009-03-05 fl Fixed rounding error in grayscale calculation
13#
14# Copyright (c) 2002-2004 by Secret Labs AB
15# Copyright (c) 2002-2004 by Fredrik Lundh
16#
17# See the README file for information on usage and redistribution.
18#
19from __future__ import annotations
21import re
22from functools import lru_cache
24from . import Image
27@lru_cache
28def getrgb(color):
29 """
30 Convert a color string to an RGB or RGBA tuple. If the string cannot be
31 parsed, this function raises a :py:exc:`ValueError` exception.
33 .. versionadded:: 1.1.4
35 :param color: A color string
36 :return: ``(red, green, blue[, alpha])``
37 """
38 if len(color) > 100:
39 msg = "color specifier is too long"
40 raise ValueError(msg)
41 color = color.lower()
43 rgb = colormap.get(color, None)
44 if rgb:
45 if isinstance(rgb, tuple):
46 return rgb
47 colormap[color] = rgb = getrgb(rgb)
48 return rgb
50 # check for known string formats
51 if re.match("#[a-f0-9]{3}$", color):
52 return int(color[1] * 2, 16), int(color[2] * 2, 16), int(color[3] * 2, 16)
54 if re.match("#[a-f0-9]{4}$", color):
55 return (
56 int(color[1] * 2, 16),
57 int(color[2] * 2, 16),
58 int(color[3] * 2, 16),
59 int(color[4] * 2, 16),
60 )
62 if re.match("#[a-f0-9]{6}$", color):
63 return int(color[1:3], 16), int(color[3:5], 16), int(color[5:7], 16)
65 if re.match("#[a-f0-9]{8}$", color):
66 return (
67 int(color[1:3], 16),
68 int(color[3:5], 16),
69 int(color[5:7], 16),
70 int(color[7:9], 16),
71 )
73 m = re.match(r"rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$", color)
74 if m:
75 return int(m.group(1)), int(m.group(2)), int(m.group(3))
77 m = re.match(r"rgb\(\s*(\d+)%\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)$", color)
78 if m:
79 return (
80 int((int(m.group(1)) * 255) / 100.0 + 0.5),
81 int((int(m.group(2)) * 255) / 100.0 + 0.5),
82 int((int(m.group(3)) * 255) / 100.0 + 0.5),
83 )
85 m = re.match(
86 r"hsl\(\s*(\d+\.?\d*)\s*,\s*(\d+\.?\d*)%\s*,\s*(\d+\.?\d*)%\s*\)$", color
87 )
88 if m:
89 from colorsys import hls_to_rgb
91 rgb = hls_to_rgb(
92 float(m.group(1)) / 360.0,
93 float(m.group(3)) / 100.0,
94 float(m.group(2)) / 100.0,
95 )
96 return (
97 int(rgb[0] * 255 + 0.5),
98 int(rgb[1] * 255 + 0.5),
99 int(rgb[2] * 255 + 0.5),
100 )
102 m = re.match(
103 r"hs[bv]\(\s*(\d+\.?\d*)\s*,\s*(\d+\.?\d*)%\s*,\s*(\d+\.?\d*)%\s*\)$", color
104 )
105 if m:
106 from colorsys import hsv_to_rgb
108 rgb = hsv_to_rgb(
109 float(m.group(1)) / 360.0,
110 float(m.group(2)) / 100.0,
111 float(m.group(3)) / 100.0,
112 )
113 return (
114 int(rgb[0] * 255 + 0.5),
115 int(rgb[1] * 255 + 0.5),
116 int(rgb[2] * 255 + 0.5),
117 )
119 m = re.match(r"rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$", color)
120 if m:
121 return int(m.group(1)), int(m.group(2)), int(m.group(3)), int(m.group(4))
122 msg = f"unknown color specifier: {repr(color)}"
123 raise ValueError(msg)
126@lru_cache
127def getcolor(color, mode):
128 """
129 Same as :py:func:`~PIL.ImageColor.getrgb` for most modes. However, if
130 ``mode`` is HSV, converts the RGB value to a HSV value, or if ``mode`` is
131 not color or a palette image, converts the RGB value to a grayscale value.
132 If the string cannot be parsed, this function raises a :py:exc:`ValueError`
133 exception.
135 .. versionadded:: 1.1.4
137 :param color: A color string
138 :param mode: Convert result to this mode
139 :return: ``(graylevel[, alpha]) or (red, green, blue[, alpha])``
140 """
141 # same as getrgb, but converts the result to the given mode
142 color, alpha = getrgb(color), 255
143 if len(color) == 4:
144 color, alpha = color[:3], color[3]
146 if mode == "HSV":
147 from colorsys import rgb_to_hsv
149 r, g, b = color
150 h, s, v = rgb_to_hsv(r / 255, g / 255, b / 255)
151 return int(h * 255), int(s * 255), int(v * 255)
152 elif Image.getmodebase(mode) == "L":
153 r, g, b = color
154 # ITU-R Recommendation 601-2 for nonlinear RGB
155 # scaled to 24 bits to match the convert's implementation.
156 color = (r * 19595 + g * 38470 + b * 7471 + 0x8000) >> 16
157 if mode[-1] == "A":
158 return color, alpha
159 else:
160 if mode[-1] == "A":
161 return color + (alpha,)
162 return color
165colormap = {
166 # X11 colour table from https://drafts.csswg.org/css-color-4/, with
167 # gray/grey spelling issues fixed. This is a superset of HTML 4.0
168 # colour names used in CSS 1.
169 "aliceblue": "#f0f8ff",
170 "antiquewhite": "#faebd7",
171 "aqua": "#00ffff",
172 "aquamarine": "#7fffd4",
173 "azure": "#f0ffff",
174 "beige": "#f5f5dc",
175 "bisque": "#ffe4c4",
176 "black": "#000000",
177 "blanchedalmond": "#ffebcd",
178 "blue": "#0000ff",
179 "blueviolet": "#8a2be2",
180 "brown": "#a52a2a",
181 "burlywood": "#deb887",
182 "cadetblue": "#5f9ea0",
183 "chartreuse": "#7fff00",
184 "chocolate": "#d2691e",
185 "coral": "#ff7f50",
186 "cornflowerblue": "#6495ed",
187 "cornsilk": "#fff8dc",
188 "crimson": "#dc143c",
189 "cyan": "#00ffff",
190 "darkblue": "#00008b",
191 "darkcyan": "#008b8b",
192 "darkgoldenrod": "#b8860b",
193 "darkgray": "#a9a9a9",
194 "darkgrey": "#a9a9a9",
195 "darkgreen": "#006400",
196 "darkkhaki": "#bdb76b",
197 "darkmagenta": "#8b008b",
198 "darkolivegreen": "#556b2f",
199 "darkorange": "#ff8c00",
200 "darkorchid": "#9932cc",
201 "darkred": "#8b0000",
202 "darksalmon": "#e9967a",
203 "darkseagreen": "#8fbc8f",
204 "darkslateblue": "#483d8b",
205 "darkslategray": "#2f4f4f",
206 "darkslategrey": "#2f4f4f",
207 "darkturquoise": "#00ced1",
208 "darkviolet": "#9400d3",
209 "deeppink": "#ff1493",
210 "deepskyblue": "#00bfff",
211 "dimgray": "#696969",
212 "dimgrey": "#696969",
213 "dodgerblue": "#1e90ff",
214 "firebrick": "#b22222",
215 "floralwhite": "#fffaf0",
216 "forestgreen": "#228b22",
217 "fuchsia": "#ff00ff",
218 "gainsboro": "#dcdcdc",
219 "ghostwhite": "#f8f8ff",
220 "gold": "#ffd700",
221 "goldenrod": "#daa520",
222 "gray": "#808080",
223 "grey": "#808080",
224 "green": "#008000",
225 "greenyellow": "#adff2f",
226 "honeydew": "#f0fff0",
227 "hotpink": "#ff69b4",
228 "indianred": "#cd5c5c",
229 "indigo": "#4b0082",
230 "ivory": "#fffff0",
231 "khaki": "#f0e68c",
232 "lavender": "#e6e6fa",
233 "lavenderblush": "#fff0f5",
234 "lawngreen": "#7cfc00",
235 "lemonchiffon": "#fffacd",
236 "lightblue": "#add8e6",
237 "lightcoral": "#f08080",
238 "lightcyan": "#e0ffff",
239 "lightgoldenrodyellow": "#fafad2",
240 "lightgreen": "#90ee90",
241 "lightgray": "#d3d3d3",
242 "lightgrey": "#d3d3d3",
243 "lightpink": "#ffb6c1",
244 "lightsalmon": "#ffa07a",
245 "lightseagreen": "#20b2aa",
246 "lightskyblue": "#87cefa",
247 "lightslategray": "#778899",
248 "lightslategrey": "#778899",
249 "lightsteelblue": "#b0c4de",
250 "lightyellow": "#ffffe0",
251 "lime": "#00ff00",
252 "limegreen": "#32cd32",
253 "linen": "#faf0e6",
254 "magenta": "#ff00ff",
255 "maroon": "#800000",
256 "mediumaquamarine": "#66cdaa",
257 "mediumblue": "#0000cd",
258 "mediumorchid": "#ba55d3",
259 "mediumpurple": "#9370db",
260 "mediumseagreen": "#3cb371",
261 "mediumslateblue": "#7b68ee",
262 "mediumspringgreen": "#00fa9a",
263 "mediumturquoise": "#48d1cc",
264 "mediumvioletred": "#c71585",
265 "midnightblue": "#191970",
266 "mintcream": "#f5fffa",
267 "mistyrose": "#ffe4e1",
268 "moccasin": "#ffe4b5",
269 "navajowhite": "#ffdead",
270 "navy": "#000080",
271 "oldlace": "#fdf5e6",
272 "olive": "#808000",
273 "olivedrab": "#6b8e23",
274 "orange": "#ffa500",
275 "orangered": "#ff4500",
276 "orchid": "#da70d6",
277 "palegoldenrod": "#eee8aa",
278 "palegreen": "#98fb98",
279 "paleturquoise": "#afeeee",
280 "palevioletred": "#db7093",
281 "papayawhip": "#ffefd5",
282 "peachpuff": "#ffdab9",
283 "peru": "#cd853f",
284 "pink": "#ffc0cb",
285 "plum": "#dda0dd",
286 "powderblue": "#b0e0e6",
287 "purple": "#800080",
288 "rebeccapurple": "#663399",
289 "red": "#ff0000",
290 "rosybrown": "#bc8f8f",
291 "royalblue": "#4169e1",
292 "saddlebrown": "#8b4513",
293 "salmon": "#fa8072",
294 "sandybrown": "#f4a460",
295 "seagreen": "#2e8b57",
296 "seashell": "#fff5ee",
297 "sienna": "#a0522d",
298 "silver": "#c0c0c0",
299 "skyblue": "#87ceeb",
300 "slateblue": "#6a5acd",
301 "slategray": "#708090",
302 "slategrey": "#708090",
303 "snow": "#fffafa",
304 "springgreen": "#00ff7f",
305 "steelblue": "#4682b4",
306 "tan": "#d2b48c",
307 "teal": "#008080",
308 "thistle": "#d8bfd8",
309 "tomato": "#ff6347",
310 "turquoise": "#40e0d0",
311 "violet": "#ee82ee",
312 "wheat": "#f5deb3",
313 "white": "#ffffff",
314 "whitesmoke": "#f5f5f5",
315 "yellow": "#ffff00",
316 "yellowgreen": "#9acd32",
317}