drawSplineGradient = (colors, opts = {}) => {
const {
space = 'CIELAB',
jitter = true,
closed = false,
tension = 0.5,
type = 'uniform'
} = opts;
let from = (a) => a;
let to = (a) => a;
let jitterInSpace = a => a.map(n => n + randomGaussian(0, 0.5));
if (space === 'LinearRGB') {
from = rgb => rgb.map(n => sRGB.gammaToLinear(n / 255));
to = srgb => srgb.map(n => Math.round(255 * sRGB.linearToGamma(n)));
jitterInSpace = a => a.map(n => n + randomGaussian(0, 0.002));
} else if (space === 'CIELAB') {
from = rgb => LabConvert.rgb2lab(rgb);
to = lab => LabConvert.lab2rgb(lab);
jitterInSpace = lab => jitterLab(lab, 0.5);
} else if (space === 'Oklab') {
from = rgb => {
const srgb = rgb.map(n => sRGB.gammaToLinear(n / 255));
const { L, a, b } = oklab.sRGBToOklab({ r: srgb[0], g: srgb[1], b: srgb[2] });
return [ L, a, b ];
};
to = ([ L, a, b ]) => {
const rgb = oklab.oklabTosRGB({ L, a, b });
const srgb = [ rgb.r, rgb.g, rgb.b ];
return srgb.map(n => Math.round(255 * sRGB.linearToGamma(n)));
};
jitterInSpace = (lab) => jitterLab(lab, 0.005);
} else if (space === 'XYB') {
from = rgb => XYBConvert.rgb2xyb(rgb);
to = xyb => XYBConvert.xyb2rgb(xyb);
jitterInSpace = xyb => xyb.map(n => n + randomGaussian(0, 0.0005));
} else if (space === 'Jzazbz') {
const displayWhiteLuminance = 10000;
from = rgb => {
const srgb = rgb.map(n => n / 255);
const xyz_abs = srgb_to_xyz(srgb).map(n => n * displayWhiteLuminance / 100);
return Jzazbz.forward(xyz_abs);
};
to = Jab => {
const xyz_abs = Jzazbz.inverse(Jab);
const srgb = xyz_to_srgb(xyz_abs.map(n => n / displayWhiteLuminance * 100));
return srgb.map(n => Math.max(0, Math.min(255, Math.round(n * 255))));
};
jitterInSpace = Jab => Jab.map(n => n + randomGaussian(0, 0.0025));
}
const points = colors.map(rgb => from(rgb));
const spline = CatmullRomSpline(points, {
closed,
tension,
type
});
return ramp(u => {
const sample = spline.getPoint(u);
let point = jitter ? jitterInSpace(sample) : sample;
return to(point);
});
};