|
| 1 | +from typing import Union, Tuple |
| 2 | + |
| 3 | +from PIL import ImageColor |
| 4 | + |
| 5 | +RGBColor = Tuple[int, int, int] |
| 6 | + |
| 7 | +# Color can be an RGB tuple (RGBColor), or a string in any of these formats: |
| 8 | +# - "r, g, b" (e.g. "255, 0, 0"), as is found in the themes' yaml settings |
| 9 | +# - any of the formats supported by PIL: https://pillow.readthedocs.io/en/stable/reference/ImageColor.html |
| 10 | +# |
| 11 | +# For example, here are multiple ways to write the pure red color: |
| 12 | +# - (255, 0, 0) |
| 13 | +# - "255, 0, 0" |
| 14 | +# - "#ff0000" |
| 15 | +# - "red" |
| 16 | +# - "hsl(0, 100%, 50%)" |
| 17 | +Color = Union[str, RGBColor] |
| 18 | + |
| 19 | +def parse_color(color: Color) -> RGBColor: |
| 20 | + # even if undocumented, let's be nice and accept a list in lieu of a tuple |
| 21 | + if isinstance(color, tuple) or isinstance(color, list): |
| 22 | + if len(color) != 3: |
| 23 | + raise ValueError("RGB color must have 3 values") |
| 24 | + return (int(color[0]), int(color[1]), int(color[2])) |
| 25 | + |
| 26 | + if not isinstance(color, str): |
| 27 | + raise ValueError("Color must be either an RGB tuple or a string") |
| 28 | + |
| 29 | + # Try to parse it as our custom "r, g, b" format |
| 30 | + rgb = color.split(',') |
| 31 | + if len(rgb) == 3: |
| 32 | + r, g, b = rgb |
| 33 | + try: |
| 34 | + rgbcolor = (int(r.strip()), int(g.strip()), int(b.strip())) |
| 35 | + except ValueError: |
| 36 | + # at least one element can't be converted to int, we continue to |
| 37 | + # try parsing as a PIL color |
| 38 | + pass |
| 39 | + else: |
| 40 | + return rgbcolor |
| 41 | + |
| 42 | + # fallback as a PIL color |
| 43 | + rgbcolor = ImageColor.getrgb(color) |
| 44 | + if len(rgbcolor) == 4: |
| 45 | + return (rgbcolor[0], rgbcolor[1], rgbcolor[2]) |
| 46 | + return rgbcolor |
| 47 | + |
0 commit comments