pub fn gradient_unpremultiplied<CS: ColorSpace>(
color0: DynamicColor,
color1: DynamicColor,
interp_cs: ColorSpaceTag,
direction: HueDirection,
tolerance: f32,
) -> UnpremultipliedGradientIter<CS> ⓘExpand description
Generate a piecewise linear approximation to a gradient ramp without alpha premultiplication.
Similar to gradient, but colors are interpolated without premultiplying their color
channels by the alpha channel. This is almost never what you want.
This causes color information to leak out of transparent colors. For example, when interpolating from a fully transparent red to a fully opaque blue in sRGB, this method will go through an intermediate purple.
This matches behavior of gradients in the HTML canvas element.
See The 2D rendering context § Fill and stroke styles of the
HTML 2D Canvas specification.
§Example
The following compares interpolating in the target color space Oklab with interpolating piecewise in the color space sRGB.
use color::{AlphaColor, ColorSpaceTag, DynamicColor, HueDirection, Oklab, Srgb};
let start = DynamicColor::from_alpha_color(AlphaColor::<Srgb>::new([1., 0., 0., 1.]));
let end = DynamicColor::from_alpha_color(AlphaColor::<Srgb>::new([0., 1., 0., 1.]));
// Interpolation in a target interpolation color space.
let interp = start.interpolate_unpremultiplied(end, ColorSpaceTag::Oklab, HueDirection::default());
// Piecewise-approximated interpolation in a compositing color space.
let mut gradient = color::gradient_unpremultiplied::<Srgb>(
start,
end,
ColorSpaceTag::Oklab,
HueDirection::default(),
0.01,
);
let (mut t0, mut stop0) = gradient.next().unwrap();
for (t1, stop1) in gradient {
// Compare a few points between the piecewise stops.
for point in [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9] {
let interpolated_point = interp
.eval(t0 + (t1 - t0) * point)
.to_alpha_color::<Srgb>()
.discard_alpha();
let approximated_point = stop0.lerp_rect(stop1, point).discard_alpha();
// The perceptual deltaEOK between the two is lower than the tolerance.
assert!(
approximated_point
.convert::<Oklab>()
.difference(interpolated_point.convert::<Oklab>())
< 0.01
);
}
t0 = t1;
stop0 = stop1;
}