Re: [whatwg] Canvas gradients color interpolation - change to premultiplied?
On Fri, Nov 26, 2010 at 8:44 PM, Boris Zbarsky bzbar...@mit.edu wrote: On 11/26/10 11:39 PM, Simon Fraser wrote: But CSS gradients are already requiring interpolation in premutiplied space, right? I think you're thinking of CSS Transitions, which we decided should run in premultiplied. No. http://dev.w3.org/csswg/css3-images/#color-stop-syntax currently says: Between two color-stops, the line's color is linearly interpolated between the colors of the two color-stops, with the interpolation taking place in premultiplied RGBA space. and there was related discussion on www-style, iirc. Note, though, that that's a relatively recent change that I made based on dbaron's feedback. That said, in the thread where I made the change, Simon expressed that he'd like Transitions and Gradients to work the same way, and I read him as preferring premultiplied. ~TJ
Re: [whatwg] Canvas gradients color interpolation - change to premultiplied?
On Nov 23, 2010, at 12:43 PM, Tab Atkins Jr. wrote: Implementors, does this sounds like a change you can get behind? We already changed canvas shadows to match behavior with CSS shadows; this is a much smaller change for spec-equivalence. This would be hard for WebKit, which relies on Core Graphics for gradients on some platforms. CG doesn't allow us to interpolate in premultiplied space. [Of course, some of the new radial gradient stuff is also not doable using CG, so maybe we'll have to have a slower non-CG gradient code path anyway]. Simon
Re: [whatwg] Canvas gradients color interpolation - change to premultiplied?
On 11/26/10 4:09 PM, Simon Fraser wrote: This would be hard for WebKit, which relies on Core Graphics for gradients on some platforms. CG doesn't allow us to interpolate in premultiplied space. But CSS gradients are already requiring interpolation in premutiplied space, right? -Boris
Re: [whatwg] Canvas gradients color interpolation - change to premultiplied?
On Nov 26, 2010, at 6:38 PM, Boris Zbarsky bzbar...@mit.edu wrote: On 11/26/10 4:09 PM, Simon Fraser wrote: This would be hard for WebKit, which relies on Core Graphics for gradients on some platforms. CG doesn't allow us to interpolate in premultiplied space. But CSS gradients are already requiring interpolation in premutiplied space, right? I think you're thinking of CSS Transitions, which we decided should run in premultiplied. Simon
Re: [whatwg] Canvas gradients color interpolation - change to premultiplied?
On 11/26/10 11:39 PM, Simon Fraser wrote: But CSS gradients are already requiring interpolation in premutiplied space, right? I think you're thinking of CSS Transitions, which we decided should run in premultiplied. No. http://dev.w3.org/csswg/css3-images/#color-stop-syntax currently says: Between two color-stops, the line's color is linearly interpolated between the colors of the two color-stops, with the interpolation taking place in premultiplied RGBA space. and there was related discussion on www-style, iirc. -Boris
Re: [whatwg] Canvas gradients color interpolation - change to premultiplied?
On Tue, 23 Nov 2010 23:09:40 +0100, Philip Taylor excors+wha...@gmail.com wrote: On Tue, Nov 23, 2010 at 8:43 PM, Tab Atkins Jr. jackalm...@gmail.com wrote: 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 rgba(255,255,0,.5).* 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 http://annevankesteren.nl/
Re: [whatwg] Canvas gradients color interpolation - change to premultiplied?
On 11/25/10 1:59 PM, Anne van Kesteren wrote: They also pointed out we do support rgba() in SVG. The point is that the resulting behavior is not defined by the SVG spec. You could blow up the user's computer when using an rgba() color in SVG, and that would be as spec-compliant as anything else... -Boris
Re: [whatwg] Canvas gradients color interpolation - change to premultiplied?
On Tue, Nov 23, 2010 at 8:43 PM, Tab Atkins Jr. jackalm...@gmail.com wrote: 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 rgba(255,255,0,.5).* 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.) -- Philip Taylor exc...@gmail.com
Re: [whatwg] Canvas gradients color interpolation - change to premultiplied?
On Tue, Nov 23, 2010 at 2:09 PM, Philip Taylor excors+wha...@gmail.com wrote: On Tue, Nov 23, 2010 at 8:43 PM, Tab Atkins Jr. jackalm...@gmail.com wrote: 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 rgba(255,255,0,.5).* 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. For what it's worth, I suspect most people don't think of transparent as transparent black, but rather as fully see-through. / Jonas
Re: [whatwg] Canvas gradients color interpolation - change to premultiplied?
On Tue, Nov 23, 2010 at 2:09 PM, Philip Taylor excors+wha...@gmail.com wrote: On Tue, Nov 23, 2010 at 8:43 PM, Tab Atkins Jr. jackalm...@gmail.com wrote: 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 rgba(255,255,0,.5).* 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 fact that transparent means transparent black is a technical detail that is usually irrelevant. A fully transparent color doesn't really have a color at all. I'm highly technical, involved in the relevant specs, and understand the underlying math, and I *still* get tripped up over the fact that transparent is black. 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. Luckily I didn't say that SVG used premultiplied colors. ^_^ I said they end up interpolating in a similar way, if you do the obvious thing and just adjust the opacity. When using CSS colors, the obvious thing is to use the transparent keyword, which gives unsatisfactory behavior most of the time if you transition in plain rgba space. 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. Possibly, but that can't be fixed now, and so as a result both Transitions/Animations and Gradients use premultiplied colors, and won't likely change (I know that Apple and Moz support using premultiplied colors in transitions and gradients). Making canvas gradients match CSS seems like a better idea than the reverse at this point, and seems more likely to have implementor support. (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.) This is incompatible with both gradients and transitions (actually, animations), because transparent can be simultaneously the endpoints of two different color interpolations. An animation or a gradient can go from a solid color to transparent to a solid color again. While it's theoretically possible in a red-transparent-blue animation/gradient to have transparent mean rgba(255,0,0,0) when going from red-transparent, and then mean rgba(0,0,255,0) when going from transparent-blue, that's hacky and weird. Doing it in premultiplied space makes it all happen cleanly and automatically. ~TJ
Re: [whatwg] Canvas gradients color interpolation - change to premultiplied?
On Tuesday 2010-11-23 22:09 +, Philip Taylor wrote: On Tue, Nov 23, 2010 at 8:43 PM, Tab Atkins Jr. jackalm...@gmail.com wrote: 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 rgba(255,255,0,.5).* 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. Sure, you can solve that particular case. However, if neither of the endpoints is precisely transparent, and you're changing both color and alpha components, you'll still get an ugly effect with the current rules, and one that you can't work around. (I experimented with both methods when implementing CSS transitions of colors, and went with premultiplied. http://dbaron.org/css/test/2009/transitions/transitions-alpha makes it look like WebKit has now switched to premultiplied.) That sounds like SVG gradients *can't* be using premultiplied colours. Yes, because SVG doesn't have RGBA colors; it has RGB colors (in stop-color) and a separate stop-opacity property/attribute. So the choice doesn't apply to SVG. 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. It's not only the 'transparent' keyword; it affects all cases of gradients between colors with different alpha values and different color values. And in cases where one of the endpoint alphas is not 0, it's not possible to get the correct (premultiplied) result with a gradient computed in nonpremultiplied space. -David -- L. David Baron http://dbaron.org/ Mozilla Corporation http://www.mozilla.com/