20

I want to implement color blending as described in the W3C compositing and blending spec. (I'm doing this in JavaScript but the language shouldn't really matter for solving my problem.)


In retrospect: During the implementation of the answer to this question I realized that this would probably make for a pretty nice standalone package. In case you're interested you can grab it from npm.


It worked out pretty well so far but I wanted to take these algorithms a step further and add support for alpha channels. Thanks to the SVG compositing spec providing all the needed formulas that wasn't too hard.

But now I'm stuck with implementing the blend modes that the W3C spec describes as non-separable which are (as known from Photoshop): hue, saturation, color and luminosity.

Sadly, algorithms for those aren't available in the SVG spec and I have no idea how to work with those. I guess there are a modified versions of the formulas provided by the W3C for working with alpha channels which I'm missing.

To make my problem a little more visual I'll show what Photoshop gives me for hue blending two colors:

Photoshop hue blending example of two opaque colors

This is what I'm also able to reproduce with the non-alpha algorithm from the mentioned W3C spec.

What I can't reproduce is the result that Photoshop gives me when I put a lower alpha on both the source and the backdrop color:

Photoshop hue blending example of two colors with 60% opacity each

Does anyone know how to achieve that result programmatically?

Update 1: Changed illustrations (adding HSVA and RGBA codes) to clarify the used colors.

Update 2: To check possible solutions I'll attach two other Photoshop-generated blending examples:

Photoshop hue blending example of two colors with different opacity combinations

Photoshop hue blending example of two colors with different opacity combinations

Update 3: So it turned out that in addition to not having a clue about color blending I also messed up my Photoshop settings, making the task to solve my question even harder. Fixed the example images for possible future passerbies.

Community
  • 1
  • 1
Loilo
  • 13,466
  • 8
  • 37
  • 47
  • 1
    I spent a very long time back in 1997 reverse engineering all the Photoshop blend modes, including the effect of alpha. Unfortunately it's all the property of a company that I haven't worked for in years. – Mark Ransom Nov 28 '16 at 23:53
  • Photoshop's blend modes use a different color space than the actual spec'ed HSL or HSV (despite being called the same). The operations use a gamut mapping and are uninvertible in general. Detailed info on this looks scarce (proprietary), but you can read more here: https://en.wikipedia.org/wiki/Blend_modes#Hue.2C_saturation_and_luminosity – Special Sauce Nov 29 '16 at 19:22
  • @SpecialSauce Yep, already read that, thanks for pointing it out though. However it should still be possible to resemble Photoshop's behaviour with "regular" color spaces (which is also implied by Mark Ransom's comment above). – Loilo Nov 29 '16 at 22:09
  • Are the hsla numbers in your example produced by Photoshop or something else? I notice that they don't resemble the numbers from the formulas at your w3 link. And the `SetSat` function at that link is completely wrong in my opinion. – Mark Ransom Nov 30 '16 at 05:19
  • @MarkRansom The HSLA values are from the color converter at colormine.org, feeded with Photoshop's HSB data since Photoshop (CS6 at least) doesn't support the HSL colorspace. I'm not sure about those w3 functions but without any alpha channels they do actually work pretty well. – Loilo Nov 30 '16 at 09:36
  • 1
    Wouldn't it be possible to get few examples and try to guess the equation from result? Mathematically I assume we have a function which takes 8 arguments (4 source and 4 backdrop) and returns 4 variables, is that correct? – piotrwest Nov 30 '16 at 11:37
  • @piotrwest That's definitely possible in theory but realistically that should be really harsh if you don't know at least partly what exactly you're looking for. Look at the W3C algorithm I've linked, I most definitely couldn't come up with anything similar just by looking at results. – Loilo Nov 30 '16 at 11:55
  • I finally figured out why `SetSat` works - you can't use it on it's own, you *must* pair it with `SetLum`. Can you give us the RGBA values for the 3 colors in your second example? – Mark Ransom Dec 02 '16 at 04:32
  • Of course, I'm going to edit my question accordingly. – Loilo Dec 02 '16 at 16:39
  • When you say programmatically, I suppose you mean javascript, can you confirm please? – Ivan Chaer Dec 02 '16 at 16:40
  • I'm doing this in JavaScript and I want to achieve it in JavaScript, yes. But the language shouldn't matter that much because it should boil down to math anyway. – Loilo Dec 02 '16 at 16:55
  • Had to delete my answer -- since you filled in the RGB values, I can't imagine how they're derived. – Matt Timmermans Dec 03 '16 at 02:48
  • You might find http://stackoverflow.com/questions/5343629/averaging-angles useful for blending hues. – Mark Ransom Dec 04 '16 at 01:51
  • @maraca You're right of course, seems I messed up the HSLA codes, fixed that. – Loilo Dec 04 '16 at 10:44
  • @MarkRansom I haven't had a question yet where the bounty wasn't claimed after seven days but since there's no usable answer until now I guess the bounty reputation will go back to me and I can just add another one? – Loilo Dec 04 '16 at 11:04
  • @Loilo you never get your points back, whether you reward them or not. It prevents abusing the system I guess. – maraca Dec 04 '16 at 13:38
  • Good too know, even if it's kind of sad. – Loilo Dec 04 '16 at 17:24
  • I'm still interested in answering this question, even without a bounty. Do you think you could add more examples, especially ones where the saturation and luminance are farther apart? P.S. your alpha is wrong on the example with a=1 on the backdrop, should be a=1 on the result as well. – Mark Ransom Dec 05 '16 at 02:25
  • 1
    @MarkRansom Wow, seems I'm way too unwary with my images... I'll fix that one. Of course you may answer this question but I'm not sure what it would contain that has not been said yet by Christos Lytras' answer. I'll attach another example though. – Loilo Dec 05 '16 at 10:51

2 Answers2

17

The Hue alpha you have at your second image does not represent the alpha color composition formula, but it rather reflects the Porter Duff alpha composition Source Over as defined here 9.1.4. Source Over and it uses the following formula:

Source Over Formula

If you want to achieve that kind of blending, which is not proper Hue blending, you can use the following formula in javascript:

PDso = { // Ported Duff Source Over
    r: ((S.r * S.a) + (B.r * B.a) * (1 - S.a)) / aR,
    g: ((S.g * S.a) + (B.g * B.a) * (1 - S.a)) / aR,
    b: ((S.b * S.a) + (B.b * B.a) * (1 - S.a)) / aR,
};

// where
// S : the source rgba
// B : the backdrop rgba
// aR : the union alpha (as + ab * (1 - as))

Hue Blending Mode with Alpha Channel

Here is a screenshot of the exact hue blend source over backdrop using the alpha color composition formula that I have created in Photoshop:

Photoshop Hue Blend Mode

The middle square with the green highlighted letters is the correct blend representation. Here is the CSS Hue mix blend with the source color inside the backdrop color, using the new CSS mix-blend-mode (run the code snippet):

.blends div {
    width:140px;
    height:140px;
}

.source {
    mix-blend-mode: hue;
}

.backdrop.alpha {
    background-color: rgba(141, 214, 214, .6);
    isolation: isolate;
}

.source.alpha {
    background-color: rgba(255, 213, 0, .6);
}
<div id="main">
 
 <div class="blends alpha">
  <div class="backdrop alpha">
   <div class="source alpha"></div>
  </div>
 </div>

</div>

If you use a color picker, you'll get almost the same values (211, 214, 140 <> 210, 214, 140). That can be due to slightly different algorithms, or different rounding methods, but it doesn't really matter. The fact is, that this is the correct result when blending alpha colors with hue blend mode.

So, now we need the formula to have the proper color values for the alpha color composition applied to our hue blend mode. I have searched a little bit and I found everything inside the Adobe Document management - Portable document format - Part 1: PDF 1.7. We can find the color composition formula at the page 328 after the Blend Modes:

11.3.6 Interpretation of Alpha

The colour compositing formula

Colour Compositing Formula

This is the formula I managed to get the proper and closer to Photoshop match for the Hue Blending Mode with alpha channel. I wrote it like this in javascript:

function Union(ab, as) {
    return as + ab * (1 - as);
}

function colourCompositingFormula(as, ab, ar, Cs, Cb, Bbs) {
    return (1 - (as / ar)) * Cb + (as / ar) * Math.floor((1 - ab) * Cs + ab * Bbs);
}

var aR = Union(B.a, S.a); // αr = Union(αb, αs) // Adobe PDF Format Part 1 - page 331

var Ca = {
    // Adobe PDF Format Part 1 - page 328
    r: colourCompositingFormula(S.a, B.a, aR, S.r, B.r, C.r),
    g: colourCompositingFormula(S.a, B.a, aR, S.g, B.g, C.g),
    b: colourCompositingFormula(S.a, B.a, aR, S.b, B.b, C.b)
};

// where
// C : the hue blend mode result rgb
// S : the source rgba
// B : the backdrop rgba
// aR : the union alpha (as + ab * (1 - as))
// Ca : the final result

body {
  padding:0;
  margin:0;
}

iframe {
  width: 100%;
  height: 200px;
  border:0;
  padding:0;
  margin:0;
}
<iframe src="https://zikro.gr/dbg/html/blending-modes/"></iframe>

My test example can be found here. At the 2.5 With Alpha (Hue Blending Algorithm Computed), you cay see the final hue blend mode result with alpha. It has slightly different values than Photoshop result but I got the exact same result (202, 205, 118) in Fireworks, hue blending the source and backdrop colors:

Fireworks same result

All applications have their own slightly different algorithms and maybe the formula I have used is rather old and maybe there is a newest version.

Christos Lytras
  • 36,310
  • 4
  • 80
  • 113
  • Wow. I'm impressed by the sheer amount of effort put into this answer. I tested your algorithm with different colors and opacities and the accuracy of your results is roughly the same everywhere. I must admit that the deviation from Photoshop (which as you explained CSS creates as well, I'd also already checked that before posting my question) is a bit annoying though. However there are some hours left on the grace period of the bounty, in case there won't be a more accurate answer you'll certainly earn that. – Loilo Dec 04 '16 at 20:14
  • @Loilo I know some things about colors. I have worked on some C++ applications on the past managing and blending color values. In fact I really enjoyed this Q/A here! It's been very long time I messed with all these color stuff. Btw, I see you don't know much about how bounty works. If the grace period expires and there are no accepted answer, then the answer with >= 3 upvotes gets the half of the bounty. If there is no answer with >= 3 upvotes, then all of the bounty gets lost! Please read here http://stackoverflow.com/help/bounty. If this A is what you're looking for, then please accept it. – Christos Lytras Dec 04 '16 at 21:18
  • Yes, I know those bounty things. I only took a glance at the bounty FAQ which is why I didn't get it 100% correct (regarding bounty refunds if no answer is given). After giving it some thought the lack of refunding makes complete sense of course. Regarding your answer - I'd just have waited for a maybe an even a little more accurate algorithm but since the bounty's already on grace period I guess it would just be fair to directly accept your answer. – Loilo Dec 04 '16 at 21:43
  • @Loilo thank you. I'll check for a more accurate formula and I am impressed that the *Adobe Fireworks* generates a slightly (even by `+-1 R`) different value than the *Photoshop*! Do you want to have my javascript files for *Hue blending* and *Color Hsl/Rgb*? You can get them from my source link of course, but I can even update the answer with the links or the full code if you want. – Christos Lytras Dec 04 '16 at 22:03
  • I already inspected the source and got what I needed, thank you. (I hope by reading further into it and maybe the Adobe specs I can derive similar algorithms for *saturation* and *luminosity*.) Since you mentioned Fireworks: I just tried the same in *Adobe Illustrator* and voila—the result exactly reflects your algorithmic results (rgba(202, 205, 119, 0.84), ±1 for rounding I guess). I'm not sure if this is actually an algorithmic difference in Photoshop (both applications are in version CS6 for me) or if any other factors are playing into that. – Loilo Dec 04 '16 at 22:34
  • I can confirm that *Illustrator CC 2015* gives me `202, 205, 119`! Check my updated formula. I firstly used the `Math.floor` instead of `Math.round`. With the `round` we get `202, 205, 119` the exact like *Illustrator*, but with the `floor` we get `202, 205, 118` more close to *Photoshop* `202, 206, 118`, keen in mind that. Maybe it's a *PSD Photoshop* setting similar to color format that affects the values, but I have checked and it is on RGB mode. – Christos Lytras Dec 04 '16 at 23:06
  • Wait, I guess I have misread your graphic then. `202, 206, 118` is what you're actually *getting* from Photoshop? My Photoshop (CS6) gives me `206, 206, 137` instead, that's the deviation I was complaining about. – Loilo Dec 04 '16 at 23:12
  • Yes, that's what I get from *Photoshop CC 2015*. Are you sure you have the layers *source* to `Hue` and *backdrop* to `Normal` blending modes? Look at my *Photoshop* color picker info screenshot http://zikro.gr/dbg/html/blending-modes/photoshop-ss-1lbl.png. I read the same values (`202, 206, 118, 84%`) when I open the file (saved as PNG with alpha channel) with *Fireworks*. – Christos Lytras Dec 04 '16 at 23:30
  • I'm completely sure. I read those values from your PNG as well but when I'm adding the same colors to two layers I'm getting a different result. I actually just opened your PNG and added two layers of my own to the top left, look at this: http://i.imgur.com/3OZ29vS.png – Loilo Dec 04 '16 at 23:46
  • There is something wrong then. That's not the correct values you have. Check my [Photoshop color settings](http://zikro.gr/dbg/html/blending-modes/photoshop-color-settings.png) and see yours to see if there are any differences. Also, I have updated my [test page](http://zikro.gr/dbg/html/blending-modes/) and you can find at the bottom, the links to my *PSD* and *AI* files. Download them and check the values on both. Can you please share a sample *PSD* file with that values you get? – Christos Lytras Dec 05 '16 at 00:01
  • There we got the culprit. (Spoiler: It's me.) Before I came up with this concrete example of colors I posted my question as a general issue over at StackExchange's very own *Software Engineering* platform (http://softwareengineering.stackexchange.com/questions/336794/algorithms-for-color-blending-modes-hue-saturation-color-luminosity). The pretty much only thing I got was a comment with some blog post about the *gamma* topic. During the reading of that I enabled *Blend RGB Colors Using Gamma* in Photoshop and apparently forgot to disable it again. Thanks for really spelling that out for me... – Loilo Dec 05 '16 at 00:09
  • Yes, that makes total sense! I told you at the begging of my answer that the values you got there are wrong. These at the second alpha original image are not *Hue* blended values and now you know why *smile* Be careful and always remember to change back the settings when you alter them. I saw your question at http://softwareengineering.stackexchange.com/questions/336794/algorithms-for-color-blending-modes-hue-saturation-color-luminosity and I have even read the article about *Gamma* posted on the comments! I have to admit, it was a good knowledge source but irrelevant with your problem! – Christos Lytras Dec 05 '16 at 00:24
  • That's what I thought, too. Valuable information nonetheless. Except that forgetting to turn the settings back completely ruined my understanding of your answer. I guess now you've double-earned that bounty. :) Thank you very much for your efforts! I think I'm going to do a little bit of adjustment to your answer and then put it under the general question at *SE* as well. – Loilo Dec 05 '16 at 00:28
  • It was really a pleasure to work on answering this! Feel free to copy and change my answer and post it on your SE question. There might be other people searching for all these *Blend Modes* related stuff. A thing about the formula; i had the `Union` function calculating the `αs` and `αb` with the wrong order, but it generates the correct result because both *Source* and *Backdrop* have the same alpha `.6`. The correct `Union` function is `return as + ab * (1 - as);` and its called with `αb` first and `αs` as the second parameter like this `Union(B.a, S.a) //αr = Union(αb, αs) // adb.p.331`. – Christos Lytras Dec 05 '16 at 10:32
2

Starting from here

Hue blending creates a color with the hue of the source color and the saturation and luminosity of the backdrop color.

I can come up with some formulas, but they might be rubbish, although they completely reproduce the original numbers posted:

h: hSource + deltaH * (1 - aSrouce) * aBackdrop * 0.41666666 = 50; 63

s: sBackdrop * 0.9 + deltaS * (1 - aBackdrop) * aSource * 0.20833333 = 45; 47.5

l: lBackdrop * 0.957142857 + deltaL * (1 - aBackdrop) * aSource * 0.77 = 67; 63.3

a: 1 - (1 - aSource)^2 matches always

maraca
  • 8,468
  • 3
  • 23
  • 45
  • 1
    I appreciate the effort but your formula really only solves that one particular case and is not of any use for the general problem. But it's a good idea anyway to add another Photoshop-generated blending example to the question to check possible results against that. Also your formula has at least one error in it since the calculation of deltas of hue and luminosity are a little twisted (deltaH = hBackdrop - hSource but deltaL = lSource - lBackdrop). – Loilo Dec 04 '16 at 11:03
  • That with the deltas is logically consistent. Hue takes the source as base, but luminosity and saturation the backdrop, therefore it's the other way round there. – maraca Dec 04 '16 at 13:41