Flattening Color Layers with JavaScript

Rainbow Cake (both cake and photo) by Dabbisch on Deviantart [CC BY-NC-ND 3.0]

A while ago I was trying to find an appropriate opaque fallback color for a translucent background color. Although after some thought I understand what the method is to calculate such a thing, at the time I just did a search and came across an article by Lance Gutin relating transparency and color for grayscale. I thought I might expand it to full-color, and after little time on the Mozilla Development Network and a lot in Stack Overflow and Brackets, I have a little utility for you. You can use it here or grab it on GitHub.

Since the arithmetic turned out to be straightforward and my need for this sort of calculation is infrequent, this project turned more into a way to practice non-DOM-manipulation and plain-vanilla JavaScript. My goal was for any valid color specification syntax to be acceptable, and maybe for it to be even more forgiving than that. I found the MDN pages on the color CSS data type and regular expressions in JavaScript most helpful.

Mathity Math

The simplest calculation is on an opaque background, where you take a weighted average of the color values. If the alpha of your overlay color is set to 0.8, to find the red value of the color you see (the composite color), you’ll calculate 0.8*(red value of overlay) + (1 - 0.8)*(red value of background). Do that for all three color channels and you have the code for the composite color. You can make this calculation for some opacities via the Color Blender from Eric Meyer (opacity must be a fraction with denominator less than or equal to 11).

When you add translucency as an option for the background the arithmetic increases in length but not really in complexity: the spec for simple alpha blending or compositing (which applies to both SVG and CSS) simply takes a doubly-weighted average, though it does not take the color underneath the background into account.

Here’s the fully written out calculation, for the red channel:
(composite alpha)*(composite red) = (1 - overlay alpha)*(background alpha)*(background red) + (overlay alpha)*(overlay red)
The composite color’s alpha value will be 1 - (1 - overlay alpha)*(1 - background alpha). If either background or overlay is opaque, the composite will be opaque. If the background is opaque the equation simplifies to the one we had previously; if the overlay is opaque it simplifies to composite red = overlay red.

A translucent background on an opaque bottom layer (the tallest stack I was interested in manipulating) can be dealt with in two steps: average the background and the bottom layer and then average that with the overlay.

Turns out that calculation is the simplest of the bunch, though, and extracting the color information from the assorted kinds of input permitted is much more complicated. I’ll leave that story to the code itself, though.


Rainbow Cake (both cake and photo) by Dabbisch on Deviantart [CC BY-NC-ND 3.0].

Leave a Reply

Your email address will not be published. Required fields are marked *