I need to write a JavaScript function and a SASS mixin to calculate Soft Light blended value of two colors with an alpha input.
The function / mixin will take three parameters as follows:
- Background / base color value
- Foreground / top color value
- Alpha value for the foreground / top color
and will return the blended color.
Ideally the function will look like:
function soft_light(bgcol, fgcol, alpha) {
return soft_light_blended_color;
}
Here is a reference about the Soft Light blend mode from Wikipedia. I am aiming the formula used by Photoshop.
I can't understand how the formula will be calculated. Why the value of b
is in between 0
and 1
instead of a color code? How the gamma correction thing work? How I will perform basic operations like multiplication, subtraction used in the formula with the color values.
Guides to the solution are highly appreciated. Thanks in advance. :-)
Well, you are touching upon an area assumed to be simple by many, but colorimetry (or "the science and technology used to quantify and describe physically the human color perception.") is actually a very complex area and its entire scope is understood by relatively few.
That may sound scary but, no worries, we won't need to understand its entirety for this task.
Short on normalized values
Lets start with why 0 to 1: this represents normalized values which is independent on bit-resolution (ie. 8-bit, 10-bit component values etc.). It is also needed for the linearizing process (e.g. gamma and color space) or we would end up with very wrong values. It also reduces the rounding errors when processed due to being floating point. The cons are of course a performance hit and some memory overhead.
Short on gamma
If you're using image sources you will need to know and use the gamma value for it. If the images are stored as sRGB you can assume the value to be 2.2. Although it isn't 100% accurate it's good enough for this purpose.
Gamma is a logarithmic compensating of otherwise linear color values to match how luminance appears on the screen (CRT, LCD etc.) and is applied so that when you have, say, a gray-scale gradient it will actually be perceived as being evenly progressing from black to white by our human eye.
However, all composition and blending require linear values (the middle value of the aforementioned gradient would actually be 127-128) to produce correct results, so we first need to normalize and apply inverse gamma on the values (in pseudo code - I'm using
Col
to represent all components, but each step has to be applied separately to each component):First steps (optional)
You can skip these steps if accuracy isn't that important and performance matters more.
Then apply inverse gamma (decoding gamma):
Now, we would normally use a LUT (look-up table) to do the gamma conversion but I'll keep it like this for clarity (you would in that case use it before the value is normalized, otherwise it isn't very useful).
Blending and the Photoshop formula
Now we can process the color. Blend is usually only applied to foreground (
b
orsource
) so we don't have to worry about background and alpha quite yet.The formula in the Wikipedia article is one version I have seen claiming to be the Photoshop formula.
For example, the one I possess looks like this:
And the Wikipedia's look like this:
On top of that you have W3C version which is implemented in the browser (IIRC many of the blending formulas are "donated" by Adobe, so..).
But lets stick to the one you reference (you can always replace it with one of the other if you check against Photoshop and its result to see which matches most). Also see the discussion on the formula shown in the article.
Still as pseudo (remember that
b
is foreground/top layer anda
background/bottom layer in the Wikipedia article):Compositing
Now we have our new blended foreground and it's time to composite it on the background using the alpha value. We will use the standard source-over method for this, as always with blending modes. We can use the W3C which uses standard Porter-Duff:
We will perhaps need a alpha blending step at the end (check in your case).
In the current pseudo function, that will translate into:
Gamma encoding and Normalizing
And then we need to apply gamma again so we convert linear back to logarithmic for display (your browser may already do the gamma encoding for you for display purposes, but if you need to save it out..):
Summary
So in summary, the steps are:
*: Can be skipped if accuracy can be sacrificed, but not performance.
The colors would be for example:
So the blending code would actually look like this:
Disclaimer: I did not test codes, formulas above for errors due to the large scope and I didn't intend to write-up all the code. Even if there are errors you should get the general idea. If someone finds errors, feel free to update the post directly or comment.