UNPKG

colorjs.io

Version:

Let’s get serious about color

55 lines (46 loc) 1.79 kB
import hct from "../spaces/hct.js"; import { viewingConditions } from "../spaces/hct.js"; import getColor from "../getColor.js"; /** @import { Coords } from "../types.js" */ const rad2deg = 180 / Math.PI; const deg2rad = Math.PI / 180; const ucsCoeff = [1.0, 0.007, 0.0228]; /** * Convert HCT chroma and hue (CAM16 JMh colorfulness and hue) using UCS logic for a and b. * @param {Coords} coords - HCT coordinates. * @return {number[]} */ function convertUcsAb (coords) { // We want the distance between the actual color. // If chroma is negative, it will throw off our calculations. // Normally, converting back to the base and forward will correct it. // If we have a negative chroma after this, then we have a color that // cannot resolve to positive chroma. if (coords[1] < 0) { coords = hct.fromBase(hct.toBase(coords)); } // Only in extreme cases (usually outside the visible spectrum) // can the input value for log become negative. // Avoid domain error by forcing a zero result via "max" if necessary. const M = Math.log(Math.max(1 + ucsCoeff[2] * coords[1] * viewingConditions.flRoot, 1.0)) / ucsCoeff[2]; const hrad = coords[0] * deg2rad; const a = M * Math.cos(hrad); const b = M * Math.sin(hrad); return [coords[2], a, b]; } /** * Color distance using HCT. * @param {import("../types.js").ColorTypes} color * @param {import("../types.js").ColorTypes} sample * @returns {number} */ export default function (color, sample) { [color, sample] = getColor([color, sample]); let [t1, a1, b1] = convertUcsAb(hct.from(color)); let [t2, a2, b2] = convertUcsAb(hct.from(sample)); // Use simple euclidean distance with a and b using UCS conversion // and LCh lightness (HCT tone). return Math.sqrt((t1 - t2) ** 2 + (a1 - a2) ** 2 + (b1 - b2) ** 2); }