Ogeon / palette

A Rust library for linear color calculations and conversion
Apache License 2.0
752 stars 60 forks source link

Lch color blending #178

Open piegamesde opened 4 years ago

piegamesde commented 4 years ago

Color blending in the Lch color space would be awesome to have.

Some resources and implementations I found on the way:

I didn't find much sample code, but most implementations seem to do simple linear interpolation with special wrap-around handling of the hue channel.

okaneco commented 4 years ago

You can achieve this with Mix or gradients already, it's my preferred way of blending colors too. There are some examples of gradients in the README.md and example programs at palette/examples/gradient.rs and palette/examples/readme_examples.rs.

https://docs.rs/palette/0.5.0/palette/trait.Mix.html https://docs.rs/palette/0.5.0/palette/gradient/struct.Gradient.html

Ogeon commented 4 years ago

Linear interpolation (using Mix) and gradients are already there for Lch, as mentioned. They will also do the wraparound of the hue. The difference is just in terminology, so perhaps this is more of a documentation and discovery issue.

You have probably bumped into the Blend trait, which is an implementation of the SVG blend modes, as well as the ability to extend the set of modes. I don't know if they are well defined for Lch.

I'll mark this as something that can be clarified in documentation, unless there is missing implementation. A reference to Mix and other operator traits could be added to the Blend description, for example. I'm also in the process of rewriting the readme and I think I will give an example of Mix there too.

piegamesde commented 4 years ago

Yes, I got confused, because the split into Mix and Blend operations is not something commonly done. Usually, all those operations are just summarized under "color blending". So ideally, Blend should also provide some linear mixing function*.

I don't know if they are well defined for Lch.

I don't see any reason why things like "alpha over" shouldn't be implemented for Lch. If you think of it, blending is just some special alpha multiplication and color mixing. Color mixing is already defined for Lch, and alpha multiplication can be defined as "mixing with black".

* Please note that I come from a Blender background where the definitions might be slightly different to those in painting programs.

piegamesde commented 4 years ago

What I recognize though is that the implementation of those colors will be different and cannot simply be implemented with the current version of the Blend trait, because special attention has to be paid to the hue channel. The Prisma library abstracts over those color spaces with a PolarColor trait.

Ogeon commented 4 years ago

The definitions can vary, so don't worry. Blend is implemented based on the documentation over at https://www.w3.org/TR/compositing-1/ and they do typically follow this kind of pattern:

let newColor = Rgb {
    red: some_blend_mode(a.red, b.red),
    green: some_blend_mode(a.green, b.green),
    blue: some_blend_mode(a.blue, b.blue),
};

They could in theory work for other color spaces that have the same kind of cartesian model and semantics. For other spaces, such as polar spaces and spaces with a Y/luma/brightness/lightness/value component, like Lab that doesn't have the same geometrical orientation as RGB, the mathematics of some of them (such as soft light) will have to be translated to still give the expected results without strange side effects.

The formulas specified by W3 work really well for RGB because each component has the same meaning. 0% is no light and 100% is full brightness. Spaces that have the Y/luma/brightness/lightness/value type of component are flipped 45 degrees in the RGB space (very simply put). RGB has the brightness axis as a diagonal from (0, 0, 0) to (1, 1, 1) in its color cube, while those other spaces have it from (using Lab as example) (0, 0, 0) to (1, 0, 0). Many of those blend modes would likely only operate on the brightness component, but some have to affect the hue too. That complicates things more. And it seem to be very popular to separate the brightness as its own component, compared to following the RGB pattern.

With all that in mind, I'm sure it's very much possible to implement most, if not all, of the blend modes for more spaces and make the visual outcome more or less the same. It's just not as trivial, will require some restructuring, and will have to divert from the W3 specifications in terms of the effect on the component values.

I did also give Prisma a look. Interesting, but it seems like they haven't solved this yet.

RGB is once again shown to be an odd one. I would love to have the blend mode operations work on other spaces too, if it's feasible. RGB could still follow the W3 spec, but the rest could have some kind of approximation of the visual result. It would come with the massive disclaimer that only RGB is really compliant.

This need some more research and thinking. I'll remove the documentation tag at least.

Ogeon commented 4 years ago

But I suppose the more basic modes, like normal alpha over, could still be implemented for pretty much anything. Your link with the patched GIMP version is also very interesting. It seem to tackle the same or a similar problem, so I would like to study it a bit more.

Ogeon commented 2 years ago

I'm implementing alpha compositing for Lab, the Cartesian form of Lch, in #273. The separable blend modes aren't so easy to implement for polar coordinates. The modes mentioned for GIMP would work, since they are specifically converting to HSV/HSL like values. They are however not implemented at all yet, so I will add an issue for that and refer to this from it.