Built-in data types: color (+swatch/picker)
- Dominant language
- Python
- Stars
- 133k
- Forks
- 15.7k
- Avg merge
- 1d 6h
- Merged PRs (30d)
- 155
Description
Extracted from: https://github.com/comfyanonymous/ComfyUI/issues/8821
## Feature Idea
Probably, should be a child class of [vector[3/4]](https://github.com/comfyanonymous/ComfyUI/issues/9530), but with one important distinction:
Unlike "just" vectors, colors are expressed in some colorspace. And currently, there's no "default" colorspace across the board. There are two most used ones:
- **sRGB** - for actual distributed files (jpg, png, etc.)
- **Linear** - for "professional" file types (EXR) and for proper (physically correct) color processing _(all the professional CG software recommends a so-called "linear workflow", and some - like Nuke or Houdini - don't even give an option of processing images NOT in linear space)_.
Since comfyUI frontend is in a browser, each color needs to be shown in sRGB, but MANY image operations require it's linear representation. So I suggest a following implementation:
- A `Color` ABC, with three methods/properties: `linear()`, `srgb()` and `raw()`.
- The last one shows/sets the values as they're stored in the class and shown in the fields on the node.
- The other two always return the color in the corresponding space.
- `srgb()` is used for color display in frontend.
- Two concrete classes:
- `ColorLinear`: the actual values are expressed in linear space - so what we perceive as "visually 50% gray" would actually show `[0.214, 0.214, 0.214]` as values on the node. This type's `linear()` method is just an alias for `raw()`, and `srgb()` performs conversion on call.
- `ColorSRGB` - does the opposite: `srgb()` is an alias for `raw()`, `linear()` performs the inverse conversion. The same "visually 50% gray" chosen with this data type would have `[0.5, 0.5, 0.5]`.
- As a special case, there could be a third class - a child of sRGB one, storing colors as ints - to set colors as the 0-255 values, which is well-known to Photoshop users. In this case, the fourth method/property needs to be added to all of the color classes - the one simply multiplying the output of `srgb()` by 255, and converting to int. Its value for "visually 50% gray" would be `[127, 127, 127]` (actually, it should be `127.5`, but this one is int, right?)
This is the 50% gray I'm talking about:
Ideally, there also should be a global option (in user settings) to switch the class used on all the nodes, along with a fourth class (smth like `ColorDefault`) for node authors to use in order to respect this setting.
### Widget
On the frontend, the widget needs to have 3 or 4 fields and a color swatch showing a picker window on click. The picker probably needs to be a custom one, since both Windows and Linux only let you choose an srgb-int color with their system-wide picker (there's simply no way to specify an HDR color: whether you need a "brighter than white" like `[5.0, 1.5, 0.75]` or a very dark (but not black) gray, like `0.0001`).
### Alpha
To save you from ambiguity, Alpha is always linear, regardless of what colorspace the rest of the color is expressed in. Blending one image with an alpha of 0.5 on top of another image does the perfect average of colors even in sRGB, doesn't it?
No gamma for alpha, even when PNG is saved.
## Existing Solutions
For a widget - https://github.com/Amorano/Jovimetrix
For a good example of color picker - here are screenshots from Maya, Nuke and Houdini:
## Other
To save you from the headache of researching the right color-transforming function, here's the one used by most of the professional CG software:
```python
def linear_encode_to_srgb(x: float) -> float:
"""
This is the form used in ICC’s sRGB profile.
"""
if x <= 0.003130668442500634: # the most exact cutoff
return (323/25) * x # 12.92 exactly
else:
return (211/200) * (x ** (1/2.4)) - (11/200)
def linear_color_encode_to_srgb(clr: tuple[float, float, float]) -> tuple[float, float, float]: # same transform, component-wise
return tuple(linear_encode_to_srgb(x) for x in clr)
```
If in doubt, here: https://github.com/Lex-DRL/ColorSpace-Estimate/blob/main/conversion.json
- `a` = Linear
- `f_a` = sRGB
Contributor guide
Assessment
This issue has not been assessed yet.