blend1D function
Blends a series of Color stops into steps colors (1D gradient).
This is a minimal-first port of lipgloss v2 Blend1D, but uses simple
RGB interpolation (rather than Lab) to avoid pulling in a large dependency.
If fewer than 2 blendable stops are provided, returns a list filled with the single stop (or empty if none are blendable).
Implementation
List<Color> blend1D(
int steps,
List<Color> stops, {
required bool hasDarkBackground,
}) {
if (steps < 0) steps = 0;
if (steps == 0) return const [];
if (stops.isEmpty) return const [];
// If they requested <= number of stops, return the stops (like upstream).
if (steps <= stops.length) {
return stops.take(steps).toList(growable: false);
}
final rgbStops = <cp.Rgb>[];
for (final c in stops) {
final rgb = _toRgb(c, hasDarkBackground: hasDarkBackground);
if (rgb != null) rgbStops.add(rgb);
}
if (rgbStops.isEmpty) return const [];
if (rgbStops.length == 1) {
final single = _colorFromRgb(rgbStops[0]);
return List<Color>.filled(steps, single, growable: false);
}
final numSegments = rgbStops.length - 1;
final defaultSize = steps ~/ numSegments;
final remaining = steps % numSegments;
final out = List<Color>.filled(
steps,
_colorFromRgb(rgbStops.first),
growable: false,
);
var outIndex = 0;
for (var i = 0; i < numSegments; i++) {
final from = rgbStops[i];
final to = rgbStops[i + 1];
var segmentSize = defaultSize;
if (i < remaining) segmentSize++;
final divisor = segmentSize > 1 ? (segmentSize - 1) : 1;
for (var j = 0; j < segmentSize; j++) {
final t = segmentSize > 1 ? (j / divisor) : 0.0;
final r = _lerp(from.r, to.r, t);
final g = _lerp(from.g, to.g, t);
final b = _lerp(from.b, to.b, t);
out[outIndex++] = BasicColor(_hexFromRgb(r, g, b));
if (outIndex >= steps) break;
}
}
return out;
}