| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | from __future__ import annotations |
| |
|
| | import re |
| | from functools import lru_cache |
| |
|
| | from . import Image |
| |
|
| |
|
| | @lru_cache |
| | def getrgb(color: str) -> tuple[int, int, int] | tuple[int, int, int, int]: |
| | """ |
| | Convert a color string to an RGB or RGBA tuple. If the string cannot be |
| | parsed, this function raises a :py:exc:`ValueError` exception. |
| | |
| | .. versionadded:: 1.1.4 |
| | |
| | :param color: A color string |
| | :return: ``(red, green, blue[, alpha])`` |
| | """ |
| | if len(color) > 100: |
| | msg = "color specifier is too long" |
| | raise ValueError(msg) |
| | color = color.lower() |
| |
|
| | rgb = colormap.get(color, None) |
| | if rgb: |
| | if isinstance(rgb, tuple): |
| | return rgb |
| | rgb_tuple = getrgb(rgb) |
| | assert len(rgb_tuple) == 3 |
| | colormap[color] = rgb_tuple |
| | return rgb_tuple |
| |
|
| | |
| | if re.match("#[a-f0-9]{3}$", color): |
| | return int(color[1] * 2, 16), int(color[2] * 2, 16), int(color[3] * 2, 16) |
| |
|
| | if re.match("#[a-f0-9]{4}$", color): |
| | return ( |
| | int(color[1] * 2, 16), |
| | int(color[2] * 2, 16), |
| | int(color[3] * 2, 16), |
| | int(color[4] * 2, 16), |
| | ) |
| |
|
| | if re.match("#[a-f0-9]{6}$", color): |
| | return int(color[1:3], 16), int(color[3:5], 16), int(color[5:7], 16) |
| |
|
| | if re.match("#[a-f0-9]{8}$", color): |
| | return ( |
| | int(color[1:3], 16), |
| | int(color[3:5], 16), |
| | int(color[5:7], 16), |
| | int(color[7:9], 16), |
| | ) |
| |
|
| | m = re.match(r"rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$", color) |
| | if m: |
| | return int(m.group(1)), int(m.group(2)), int(m.group(3)) |
| |
|
| | m = re.match(r"rgb\(\s*(\d+)%\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)$", color) |
| | if m: |
| | return ( |
| | int((int(m.group(1)) * 255) / 100.0 + 0.5), |
| | int((int(m.group(2)) * 255) / 100.0 + 0.5), |
| | int((int(m.group(3)) * 255) / 100.0 + 0.5), |
| | ) |
| |
|
| | m = re.match( |
| | r"hsl\(\s*(\d+\.?\d*)\s*,\s*(\d+\.?\d*)%\s*,\s*(\d+\.?\d*)%\s*\)$", color |
| | ) |
| | if m: |
| | from colorsys import hls_to_rgb |
| |
|
| | rgb_floats = hls_to_rgb( |
| | float(m.group(1)) / 360.0, |
| | float(m.group(3)) / 100.0, |
| | float(m.group(2)) / 100.0, |
| | ) |
| | return ( |
| | int(rgb_floats[0] * 255 + 0.5), |
| | int(rgb_floats[1] * 255 + 0.5), |
| | int(rgb_floats[2] * 255 + 0.5), |
| | ) |
| |
|
| | m = re.match( |
| | r"hs[bv]\(\s*(\d+\.?\d*)\s*,\s*(\d+\.?\d*)%\s*,\s*(\d+\.?\d*)%\s*\)$", color |
| | ) |
| | if m: |
| | from colorsys import hsv_to_rgb |
| |
|
| | rgb_floats = hsv_to_rgb( |
| | float(m.group(1)) / 360.0, |
| | float(m.group(2)) / 100.0, |
| | float(m.group(3)) / 100.0, |
| | ) |
| | return ( |
| | int(rgb_floats[0] * 255 + 0.5), |
| | int(rgb_floats[1] * 255 + 0.5), |
| | int(rgb_floats[2] * 255 + 0.5), |
| | ) |
| |
|
| | m = re.match(r"rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$", color) |
| | if m: |
| | return int(m.group(1)), int(m.group(2)), int(m.group(3)), int(m.group(4)) |
| | msg = f"unknown color specifier: {repr(color)}" |
| | raise ValueError(msg) |
| |
|
| |
|
| | @lru_cache |
| | def getcolor(color: str, mode: str) -> int | tuple[int, ...]: |
| | """ |
| | Same as :py:func:`~PIL.ImageColor.getrgb` for most modes. However, if |
| | ``mode`` is HSV, converts the RGB value to a HSV value, or if ``mode`` is |
| | not color or a palette image, converts the RGB value to a grayscale value. |
| | If the string cannot be parsed, this function raises a :py:exc:`ValueError` |
| | exception. |
| | |
| | .. versionadded:: 1.1.4 |
| | |
| | :param color: A color string |
| | :param mode: Convert result to this mode |
| | :return: ``graylevel, (graylevel, alpha) or (red, green, blue[, alpha])`` |
| | """ |
| | |
| | rgb, alpha = getrgb(color), 255 |
| | if len(rgb) == 4: |
| | alpha = rgb[3] |
| | rgb = rgb[:3] |
| |
|
| | if mode == "HSV": |
| | from colorsys import rgb_to_hsv |
| |
|
| | r, g, b = rgb |
| | h, s, v = rgb_to_hsv(r / 255, g / 255, b / 255) |
| | return int(h * 255), int(s * 255), int(v * 255) |
| | elif Image.getmodebase(mode) == "L": |
| | r, g, b = rgb |
| | |
| | |
| | graylevel = (r * 19595 + g * 38470 + b * 7471 + 0x8000) >> 16 |
| | if mode[-1] == "A": |
| | return graylevel, alpha |
| | return graylevel |
| | elif mode[-1] == "A": |
| | return rgb + (alpha,) |
| | return rgb |
| |
|
| |
|
| | colormap: dict[str, str | tuple[int, int, int]] = { |
| | |
| | |
| | |
| | "aliceblue": "#f0f8ff", |
| | "antiquewhite": "#faebd7", |
| | "aqua": "#00ffff", |
| | "aquamarine": "#7fffd4", |
| | "azure": "#f0ffff", |
| | "beige": "#f5f5dc", |
| | "bisque": "#ffe4c4", |
| | "black": "#000000", |
| | "blanchedalmond": "#ffebcd", |
| | "blue": "#0000ff", |
| | "blueviolet": "#8a2be2", |
| | "brown": "#a52a2a", |
| | "burlywood": "#deb887", |
| | "cadetblue": "#5f9ea0", |
| | "chartreuse": "#7fff00", |
| | "chocolate": "#d2691e", |
| | "coral": "#ff7f50", |
| | "cornflowerblue": "#6495ed", |
| | "cornsilk": "#fff8dc", |
| | "crimson": "#dc143c", |
| | "cyan": "#00ffff", |
| | "darkblue": "#00008b", |
| | "darkcyan": "#008b8b", |
| | "darkgoldenrod": "#b8860b", |
| | "darkgray": "#a9a9a9", |
| | "darkgrey": "#a9a9a9", |
| | "darkgreen": "#006400", |
| | "darkkhaki": "#bdb76b", |
| | "darkmagenta": "#8b008b", |
| | "darkolivegreen": "#556b2f", |
| | "darkorange": "#ff8c00", |
| | "darkorchid": "#9932cc", |
| | "darkred": "#8b0000", |
| | "darksalmon": "#e9967a", |
| | "darkseagreen": "#8fbc8f", |
| | "darkslateblue": "#483d8b", |
| | "darkslategray": "#2f4f4f", |
| | "darkslategrey": "#2f4f4f", |
| | "darkturquoise": "#00ced1", |
| | "darkviolet": "#9400d3", |
| | "deeppink": "#ff1493", |
| | "deepskyblue": "#00bfff", |
| | "dimgray": "#696969", |
| | "dimgrey": "#696969", |
| | "dodgerblue": "#1e90ff", |
| | "firebrick": "#b22222", |
| | "floralwhite": "#fffaf0", |
| | "forestgreen": "#228b22", |
| | "fuchsia": "#ff00ff", |
| | "gainsboro": "#dcdcdc", |
| | "ghostwhite": "#f8f8ff", |
| | "gold": "#ffd700", |
| | "goldenrod": "#daa520", |
| | "gray": "#808080", |
| | "grey": "#808080", |
| | "green": "#008000", |
| | "greenyellow": "#adff2f", |
| | "honeydew": "#f0fff0", |
| | "hotpink": "#ff69b4", |
| | "indianred": "#cd5c5c", |
| | "indigo": "#4b0082", |
| | "ivory": "#fffff0", |
| | "khaki": "#f0e68c", |
| | "lavender": "#e6e6fa", |
| | "lavenderblush": "#fff0f5", |
| | "lawngreen": "#7cfc00", |
| | "lemonchiffon": "#fffacd", |
| | "lightblue": "#add8e6", |
| | "lightcoral": "#f08080", |
| | "lightcyan": "#e0ffff", |
| | "lightgoldenrodyellow": "#fafad2", |
| | "lightgreen": "#90ee90", |
| | "lightgray": "#d3d3d3", |
| | "lightgrey": "#d3d3d3", |
| | "lightpink": "#ffb6c1", |
| | "lightsalmon": "#ffa07a", |
| | "lightseagreen": "#20b2aa", |
| | "lightskyblue": "#87cefa", |
| | "lightslategray": "#778899", |
| | "lightslategrey": "#778899", |
| | "lightsteelblue": "#b0c4de", |
| | "lightyellow": "#ffffe0", |
| | "lime": "#00ff00", |
| | "limegreen": "#32cd32", |
| | "linen": "#faf0e6", |
| | "magenta": "#ff00ff", |
| | "maroon": "#800000", |
| | "mediumaquamarine": "#66cdaa", |
| | "mediumblue": "#0000cd", |
| | "mediumorchid": "#ba55d3", |
| | "mediumpurple": "#9370db", |
| | "mediumseagreen": "#3cb371", |
| | "mediumslateblue": "#7b68ee", |
| | "mediumspringgreen": "#00fa9a", |
| | "mediumturquoise": "#48d1cc", |
| | "mediumvioletred": "#c71585", |
| | "midnightblue": "#191970", |
| | "mintcream": "#f5fffa", |
| | "mistyrose": "#ffe4e1", |
| | "moccasin": "#ffe4b5", |
| | "navajowhite": "#ffdead", |
| | "navy": "#000080", |
| | "oldlace": "#fdf5e6", |
| | "olive": "#808000", |
| | "olivedrab": "#6b8e23", |
| | "orange": "#ffa500", |
| | "orangered": "#ff4500", |
| | "orchid": "#da70d6", |
| | "palegoldenrod": "#eee8aa", |
| | "palegreen": "#98fb98", |
| | "paleturquoise": "#afeeee", |
| | "palevioletred": "#db7093", |
| | "papayawhip": "#ffefd5", |
| | "peachpuff": "#ffdab9", |
| | "peru": "#cd853f", |
| | "pink": "#ffc0cb", |
| | "plum": "#dda0dd", |
| | "powderblue": "#b0e0e6", |
| | "purple": "#800080", |
| | "rebeccapurple": "#663399", |
| | "red": "#ff0000", |
| | "rosybrown": "#bc8f8f", |
| | "royalblue": "#4169e1", |
| | "saddlebrown": "#8b4513", |
| | "salmon": "#fa8072", |
| | "sandybrown": "#f4a460", |
| | "seagreen": "#2e8b57", |
| | "seashell": "#fff5ee", |
| | "sienna": "#a0522d", |
| | "silver": "#c0c0c0", |
| | "skyblue": "#87ceeb", |
| | "slateblue": "#6a5acd", |
| | "slategray": "#708090", |
| | "slategrey": "#708090", |
| | "snow": "#fffafa", |
| | "springgreen": "#00ff7f", |
| | "steelblue": "#4682b4", |
| | "tan": "#d2b48c", |
| | "teal": "#008080", |
| | "thistle": "#d8bfd8", |
| | "tomato": "#ff6347", |
| | "turquoise": "#40e0d0", |
| | "violet": "#ee82ee", |
| | "wheat": "#f5deb3", |
| | "white": "#ffffff", |
| | "whitesmoke": "#f5f5f5", |
| | "yellow": "#ffff00", |
| | "yellowgreen": "#9acd32", |
| | } |
| |
|