Skip to content

Instantly share code, notes, and snippets.

@JordanDelcros
Created July 31, 2015 09:55
Show Gist options
  • Save JordanDelcros/518396da1c13f75ee057 to your computer and use it in GitHub Desktop.
Save JordanDelcros/518396da1c13f75ee057 to your computer and use it in GitHub Desktop.
Combine two RGBA colors with JavaScript
// Fast and easy way to combine (additive mode) two RGBA colors with JavaScript.
// [red, green, blue, alpha] based on these maximul values [255, 255, 255, 1].
var base = [69, 109, 160, 1];
var added = [61, 47, 82, 0.8];
var mix = [];
mix[3] = 1 - (1 - added[3]) * (1 - base[3]); // alpha
mix[0] = Math.round((added[0] * added[3] / mix[3]) + (base[0] * base[3] * (1 - added[3]) / mix[3])); // red
mix[1] = Math.round((added[1] * added[3] / mix[3]) + (base[1] * base[3] * (1 - added[3]) / mix[3])); // green
mix[2] = Math.round((added[2] * added[3] / mix[3]) + (base[2] * base[3] * (1 - added[3]) / mix[3])); // blue
// Will return [63, 59, 98, 1]
@PixupMedia
Copy link

@Langmans
Copy link

If the alpha value is 0, sometimes a division error is thrown.

I adapted this function so it can blend multiple colors. This is ideal if you need to calculate the rendered browser color from a stack of colors:

function blendColors() {
    var args = [].prototype.slice.call(arguments);
    var base = [0, 0, 0, 0];
    var mix;
    var added;
    while (added = args.shift()) {
        if (typeof added[3] === 'undefined') {
            added[3] = 1;
        }
        // check if both alpha channels exist.
        if (base[3] && added[3]) {
            mix = [0, 0, 0, 0];
            // alpha
            mix[3] = 1 - (1 - added[3]) * (1 - base[3]);
            // red
            mix[0] = Math.round((added[0] * added[3] / mix[3]) + (base[0] * base[3] * (1 - added[3]) / mix[3]));
            // green
            mix[1] = Math.round((added[1] * added[3] / mix[3]) + (base[1] * base[3] * (1 - added[3]) / mix[3]));
            // blue
            mix[2] = Math.round((added[2] * added[3] / mix[3]) + (base[2] * base[3] * (1 - added[3]) / mix[3]));

        } else if (added) {
            mix = added;
        } else {
            mix = base;
        }
        base = mix;
    }

    return mix;
}

// should output [85, 170, 0, 0.75]
console.log(blendColors(
    [0, 0, 0, 0],
    [255, 255, 255, 0],
    [255, 0, 0, .5],
    [0, 255, 0, .5]
));

@Langmans
Copy link

@hinell
Copy link

hinell commented Oct 24, 2017

Here is more elaborate example https://jsfiddle.net/mw7optL5/32/

<div id='box1'>base</div>
<div id='box2'>added</div>
<div id='box3'>result</div>
<style>
#box1,#box2,#box3 {
  display: inline-block;
  padding: 4em;
  width: 4em;
  text-align: center;
  background-color: orangered;
  margin: 1px;
  text-transform: uppercase;
}
</style>
<script>
var base = [260, 110, 40, 0.7];
var added = [220,170, 100,0.5];

var mix = [];
mix[3] = 1 - (1 - added[3]) * (1 - base[3]); // alpha
mix[0] = Math.round((added[0] * added[3] / mix[3]) + (base[0] * base[3] * (1 - added[3]) / mix[3])); // red
mix[1] = Math.round((added[1] * added[3] / mix[3]) + (base[1] * base[3] * (1 - added[3]) / mix[3])); // green
mix[2] = Math.round((added[2] * added[3] / mix[3]) + (base[2] * base[3] * (1 - added[3]) / mix[3])); // blue

box1.style['background-color'] = "rgba("+base.join(',')+")";
box2.style['background-color'] = "rgba("+added.join(',')+")";
box3.style['background-color'] = "rgba("+mix.join(',')+")";
</script>

@ilia3546
Copy link

Hi there. I made the Swift implementation. Maybe it will be useful for somebody.
https://gist.github.com/ilia3546/a90fcdc208b49f69be95ecd854544d73

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment