Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Color blending functions with transparency. #1704

Merged
merged 4 commits into from
Dec 8, 2013
Merged

Color blending functions with transparency. #1704

merged 4 commits into from
Dec 8, 2013

Conversation

seven-phases-max
Copy link
Member

Color blending functions now respect alpha channel with compositing and blending implemented according to this W3C draft.

Changed functions:

    multiply
    screen
    overlay
    softlight
    hardlight
    difference
    exclusion
    average
    negation

This update is a "breaking changes" one. Backward compatibility:

  • Used blending algorithms are the same as those in the old implementation except the softlight mode whose formula is gently different.
  • Since the blending algorithms are the same (but not the math itself), results for non-transparent colors passed in are similar to what the old functions return, except each color channel value may vary by +/-1 (as result of rounding applied after a math with different fp-precision side-effects, see P.S. below though).

This patch does not add any new functions. The referenced specification defines some additional blending modes not present in LESS but this is a subject for another feature-request/update and needs further discussions/decisions.

Differences from the W3C spec.:
The functions do not clamp their output (as well as input) color values despite the spec. states that:

The result of the mixing formula must be clamped to the minimum and maximum values of the color range.

Just like the old blending functions do not (as well as color operations). The rationale behind this is to allow intermediate out-of-range values inside multiple color op/blend chains e.g.:

color: (#333 + red(average(#444, (#111 - #777)));

So this update assumes that color values are clipped on final CSS output (i.e. #1693, also related #1676).
Well, in general, this whole thing of "clamping or not clamping of intermediate results" needs further discussion and may require some further changes/updates/fine-tuning, but it's somewhat out this patch scope (again) since we need to review that functionality in context of all color functions, conversions and whatever related things (for instance, contrary to color math ops and blending functions, the "Color Operations" functions like saturate always clamp their input and output values. So ideally, we'd probably like this all to be somehow unified eventually).


P.S. It is actually possible to fine-tune the new functions to output exactly the same as old values on rounding when non-transparent colors are passed in (for example the simplest way would be to just requantize the result to some reasonable precision by using something like r[i] = Math.round(cr * 2550000) / 10000; in this line). But I did not bother with this to keep the code "clean" since the whole patch is "breaking changes" anyway.

@Synchro
Copy link
Member

Synchro commented Dec 3, 2013

This is a much more elegant implementation of the blending functions, regardless of the other changes.

There have always been issues with function order because some of these operations are not commutative - for example if you spin a pure grey, you'll be left with a pure grey. How would a function get to know its context in order to apply clamping or not? Some extra param?

@seven-phases-max
Copy link
Member Author

How would a function get to know its context in order to apply clamping or not? Some extra param?

The way I see it no functions should perform clamping (at least when it's possible), the clamping is done only in the final conversion of color values to CSS string. I.e. we have already have this if #1693 is fixed.

The only exception is probably an out-of-range alpha value which may really screw most of algorithms. Well, the functions themselves never produce out-of-range alpha if their input alphas are in range, but for the moment something like this average(rgba(128, 128, 128, 50%), rgba(0, 128, 255, -200%)) is possible and may result in really weird values sometimes, but it looks like simply clamping the alpha within the "input" functions (i.e. rgba itself) should be enough and does not sound artificial.

@Synchro
Copy link
Member

Synchro commented Dec 3, 2013

The only problem I see there is that those functions are valid plain CSS as well as LESS. Is there/should there be a difference in clamping behaviour between those two contexts?

@seven-phases-max
Copy link
Member Author

#1693, there we somewhat agreed that the color output should be camped anyway. So there's no conflict regardless of context, since LESS's rgba(...) statement always goes like rgba(...) function -> internal color format -> ... -> rgba(...) CSS string , so no harm with clamping on the first step since the last step clamps anyway.

Well, actually, the more I think of alpha clamping the more it looks like it could be possible we don't even need to bother with input (or intermediate) alpha clamping at all. I did a few more tests and even if "negative opacity" is really something head-scratching from real world point of view, purely mathematically the results seem to be reasonable.

@lukeapage
Copy link
Member

I'm happy to merge this.

@Synchro are you happy?

@Synchro
Copy link
Member

Synchro commented Dec 8, 2013

Yes.

lukeapage added a commit that referenced this pull request Dec 8, 2013
…ansparency

Color blending functions with transparency.
@lukeapage lukeapage merged commit 3b1c1a5 into less:master Dec 8, 2013
@seven-phases-max seven-phases-max deleted the color-blending-with-transparency branch December 8, 2013 18:05
seven-phases-max added a commit to seven-phases-max/less-docs that referenced this pull request Dec 8, 2013
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants