pub fn gradient<CS: ColorSpace>(
color0: DynamicColor,
color1: DynamicColor,
interp_cs: ColorSpaceTag,
direction: HueDirection,
tolerance: f32,
) -> GradientIter<CS> ⓘ
Expand description
Generate a piecewise linear approximation to a gradient ramp.
The target gradient ramp is the linear interpolation from color0
to color1
in the target
color space specified by interp_cs
. For efficiency, this function returns an
iterator over color stops in the CS
color space, such that the gradient ramp
created by linearly interpolating between those stops in the CS
color space is equal within
the specified tolerance
to the target gradient ramp.
When the target interpolation color space is cylindrical, the hue can be interpolated in
multiple ways. The direction
parameter controls the way in which the hue is
interpolated.
The given tolerance
value specifies the maximum perceptual error in the approximation
measured as the Euclidean distance in the Oklab color space (see also
PremulColor::difference
). This metric is known as
deltaEOK. A reasonable value is 0.01, which in testing is nearly indistinguishable
from the exact ramp. The number of stops scales roughly as the inverse square root of the
tolerance.
The error is measured at the midpoint of each segment, which in some cases may underestimate the error.
For regular interpolation between two colors, see DynamicColor::interpolate
.
§Motivation
A major feature of CSS Color 4 is the ability to specify color interpolation in any interpolation color space CSS Color Module Level 4 § 12.1, which may be quite a bit better than simple linear interpolation in sRGB (for example).
One strategy for implementing these gradients is to interpolate in the appropriate (premultiplied) space, then map each resulting color to the space used for compositing. That can be expensive. An alternative strategy is to precompute a piecewise linear ramp that closely approximates the desired ramp, then render that using high performance techniques. This method computes such an approximation.
§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(end, ColorSpaceTag::Oklab, HueDirection::default());
// Piecewise-approximated interpolation in a compositing color space.
let mut gradient = color::gradient::<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;
}