[whatwg] Canvas gradients color interpolation - change to premultiplied?
Anne van Kesteren
annevk at opera.com
Thu Nov 25 10:59:14 PST 2010
On Tue, 23 Nov 2010 23:09:40 +0100, Philip Taylor
<excors+whatwg at gmail.com> wrote:
> On Tue, Nov 23, 2010 at 8:43 PM, Tab Atkins Jr. <jackalmage at gmail.com>
>> Right now, canvas gradients interpolate their colors in
>> non-premultiplied space; that is, the raw values of r, g, b, and a are
>> interpolated independently. This has the unfortunate effect that
>> colors darken as they transition to transparent, as "transparent" is
>> defined as "rgba(0,0,0,0)", a transparent black. Under this scheme,
>> the color halfway between "yellow" and "transparent" is
>> "rgba(127,127,0,.5)", a partially-transparent dark yellow, rather than
> If you define the gradient as interpolating from solid yellow to
> transparent black, I'd expect that it *should* be semi-transparent
> blackish-yellow in the middle.
> If you want it to be pure yellow, don't use a keyword which is
> explicitly specified as transparent black - define the gradient from
> rgba(255,255,0,1) to rgba(255,255,0,0) instead. Then you'll get
> rgba(255,255,0,0.5) in the middle.
>> The rest of the platform has switched to using premultiplied colors
>> for interpolation, because they react better in cases like this**.
>> CSS transitions and CSS gradients now explicitly use premultiplied
>> colors, and SVG ends up interpolating similarly (they don't quite have
>> the same problem - they track opacity separate from color, so
>> transitioning from "color:yellow;opacity:1" to
>> "color:yellow;opacity:0" gives you "color:yellow;opacity:.5" in the
>> middle, which is the moral equivalent of "rgba(255,255,0,.5)").
> That sounds like SVG gradients *can't* be using premultiplied colours.
> A transition from "color:yellow;opacity:1" to "color:black;opacity:0"
> will have rgba(127,127,0,0.5) in the middle, and it's impossible to
> get that if you are using premultiplied colours. You'd have to have
> A=1 at the start and A=0 at the end, so (with premultiplied colour)
> the end would be interpreted as rgba(0,0,0,0), so you'd get the same
> as interpolating to "color:yellow;opacity:0" (i.e. rgba(255,255,0,0.5)
> in the middle), which is not what SVG does.
> http://www.w3.org/TR/SVGTiny12/painting.html#Gradients says explicitly
> its behaviour is the non-premultiplied behaviour we currently get with
> canvas. ("gradient from fully transparent red, via partly transparent
> dark yellow, to fully opaque lime" - the RGB components of fully
> transparent colours are preserved.)
> Maybe CSS should have originally used the keyword "transparentblack"
> instead of "transparent" (though the distinction didn't matter before
> gradients existed) - changing the gradient algorithm solely to work
> more intuitively when people happen to use that one particular
> incorrectly-named keyword seems backwards, and a mistake in CSS.
> (Perhaps CSS gradients could avoid this problem by overriding the
> meaning of the "transparent" keyword, so that instead of rgba(0,0,0,0)
> it means A=0 with the mean RGB of the adjacent colour stops. That
> would let it work as people naturally expect when they use that
> keyword, and they can use the rgba() syntax if they really want
> transparent black or transparent yellow or transparent red etc.)
The people at Opera responsible for the graphics layer agree with Philip's
point of view. They also pointed out we do support rgba() in SVG.
Anne van Kesteren
More information about the whatwg