better-color-tools
Advanced tools
Comparing version 0.6.3 to 0.7.0
# better-color-tools | ||
## 0.7.0 | ||
### Minor Changes | ||
- ee8f8e1: Add Luv colorspace, fix Sass bugs | ||
## 0.6.3 | ||
@@ -4,0 +10,0 @@ |
@@ -22,3 +22,3 @@ export declare type HSL = [number, number, number, number]; | ||
export declare function hslTosRGB(hsl: HSL): sRGB; | ||
/** Lab -> LCh / Oklab -> Oklch)*/ | ||
/** Lab -> LCh / Oklab -> Oklch) */ | ||
export declare function labToLCH(lab: LAB): LCH; | ||
@@ -33,4 +33,2 @@ /** LCh -> Lab / Oklch -> Oklab */ | ||
export declare function linearRGBTosRGB(rgb: LinearRGB): sRGB; | ||
/** Linear sRGB -> XYZ (D65) */ | ||
export declare function linearRGBToXYZ(linearRGB: LinearRGB): XYZ_D65; | ||
/** Linear sRGB -> LMS */ | ||
@@ -56,6 +54,8 @@ export declare function linearRGBToLMS(lrgb: LinearRGB): LMS; | ||
export declare function sRGBToOklch(rgb: sRGB): Oklch; | ||
/** XYZ (D65) -> Linear sRGB */ | ||
export declare function xyzToLinearRGB(xyz: XYZ_D65): LinearRGB; | ||
/** sRGB -> XYZ (D65) */ | ||
export declare function sRGBToXYZ(rgb: sRGB): XYZ_D65; | ||
/** XYZ (D65) -> sRGB */ | ||
export declare function xyzTosRGB(xyz: XYZ_D65): LinearRGB; | ||
/** XYZ (D65) -> Luv */ | ||
export declare function xyzToLuv(xyz: XYZ_D65): LUV; | ||
export {}; |
import { clamp, degToRad, multiplyColorMatrix, radToDeg } from './utils.js'; | ||
const ε = 216 / 24389; | ||
const κ = 24389 / 27; | ||
const D65_WHITEPOINT = [95.47, 100, 108.33]; | ||
const D65_LUV_DENOMINATOR = D65_WHITEPOINT[0] + 15 * D65_WHITEPOINT[1] + 3 * D65_WHITEPOINT[2]; | ||
const D65_U_REF = (4 * D65_WHITEPOINT[0]) / D65_LUV_DENOMINATOR; | ||
const D65_V_REF = (9 * D65_WHITEPOINT[1]) / D65_LUV_DENOMINATOR; | ||
// https://bottosson.github.io/posts/oklab/ | ||
@@ -14,3 +20,3 @@ export const LMS_TO_OKLAB = [ | ||
]; | ||
// http://www.easyrgb.com/ | ||
// https://github.com/muak/ColorMinePortable/ | ||
export const LINEAR_RGB_TO_XYZ_D65 = [ | ||
@@ -75,3 +81,3 @@ [0.4124, 0.3576, 0.1805], | ||
} | ||
/** Lab -> LCh / Oklab -> Oklch)*/ | ||
/** Lab -> LCh / Oklab -> Oklch) */ | ||
export function labToLCH(lab) { | ||
@@ -125,9 +131,5 @@ const [L, a, b, alpha] = lab; | ||
else | ||
return clamp(1.055 * value ** (1 / 2.4) - 0.055, 0, 1); | ||
return clamp(1.055 * Math.pow(value, 1 / 2.4) - 0.055, 0, 1); | ||
}); | ||
} | ||
/** Linear sRGB -> XYZ (D65) */ | ||
export function linearRGBToXYZ(linearRGB) { | ||
return multiplyColorMatrix(linearRGB, LINEAR_RGB_TO_XYZ_D65); | ||
} | ||
/** Linear sRGB -> LMS */ | ||
@@ -139,14 +141,18 @@ export function linearRGBToLMS(lrgb) { | ||
export function luvToXYZ(luv) { | ||
const [L, u, v, alpha] = luv; | ||
const xyz = [0, 0, 0, alpha]; | ||
const _u = u / (13 * L); | ||
const _v = v / (13 * L); | ||
xyz[1] = L <= 8 ? L * (3 / 29) ** 3 : ((L + 16) / 116) ** 3; // Y | ||
xyz[0] = xyz[1] * (9 / 4) * _u; // X | ||
xyz[2] = xyz[1] * (((12 - 3 * _u - 20 * _v) / 4) * _v); // Z | ||
return xyz; | ||
let [L, u, v, alpha] = luv; | ||
L *= 100; | ||
u *= 100; | ||
v *= 100; | ||
const y = L > ε * κ ? ((L + 16) / 116) ** 3 : L / κ; | ||
const a = ((52 * L) / (u + 13 * L * D65_U_REF) - 1) / 3 || 0; | ||
const b = -5 * y || 0; | ||
const c = -1 / 3; | ||
const d = y * ((39 * L) / (v + 13 * L * D65_V_REF) - 5) || 0; | ||
const x = (d - b) / (a - c) || 0; | ||
const z = x * a + b; | ||
return [x, y, z, alpha]; | ||
} | ||
/** LUV -> sRGB */ | ||
export function luvTosRGB(luv) { | ||
return linearRGBTosRGB(xyzToLinearRGB(luvToXYZ(luv))); | ||
return xyzTosRGB(luvToXYZ(luv)); | ||
} | ||
@@ -184,3 +190,3 @@ /** Oklab -> LMS */ | ||
export function sRGBToLuv(rgb) { | ||
return xyzToLuv(linearRGBToXYZ(sRGBToLinearRGB(rgb))); | ||
return xyzToLuv(sRGBToXYZ(rgb)); | ||
} | ||
@@ -195,17 +201,20 @@ /** sRGB -> Oklab */ | ||
} | ||
/** XYZ (D65) -> Linear sRGB */ | ||
export function xyzToLinearRGB(xyz) { | ||
return multiplyColorMatrix(xyz, XYZ_D65_TO_LINEAR_RGB); | ||
/** sRGB -> XYZ (D65) */ | ||
export function sRGBToXYZ(rgb) { | ||
return multiplyColorMatrix(sRGBToLinearRGB(rgb), LINEAR_RGB_TO_XYZ_D65); | ||
} | ||
/** XYZ (D65) -> sRGB */ | ||
export function xyzTosRGB(xyz) { | ||
return linearRGBTosRGB(multiplyColorMatrix(xyz, XYZ_D65_TO_LINEAR_RGB)); | ||
} | ||
/** XYZ (D65) -> Luv */ | ||
export function xyzToLuv(xyz) { | ||
const [x, y, z, alpha] = xyz; | ||
const luv = [0, 0, 0, alpha]; | ||
const denominator = x + 15 * y + 3 * z; | ||
const _u = (4 * x) / denominator; | ||
const _v = (9 * y) / denominator; | ||
luv[0] = x > 0.008856451679035631 ? 116 * y ** (1 / 3) - 16 : 903.2962962962961 * y; // L | ||
luv[1] = 13 * luv[0] * _u; // u | ||
luv[2] = 13 * luv[0] * _v; // v | ||
return luv; | ||
const _u = (4 * x) / denominator || 0; | ||
const _v = (9 * y) / denominator || 0; | ||
const L = x > ε ? 116 * Math.pow(y, 1 / 3) - 16 : κ * y; | ||
const u = 13 * L * (_u - D65_U_REF) || 0; // `|| 0` fixes -0 | ||
const v = 13 * L * (_v - D65_V_REF) || 0; | ||
return [L / 100, u / 100, v / 100, alpha]; | ||
} |
@@ -1,1 +0,1 @@ | ||
function m(t,e=2){let n=t;for(;n.length<e;)n=`0${n}`;return n}function q(t){return t*(Math.PI/180)}function S(t){return t*(180/Math.PI)}function s(t,e,n){return Math.min(Math.max(t,e),n)}function G(t,e){return`color(${t} ${p(e[0],5)} ${p(e[1],5)} ${p(e[2],5)}${e[3]<1?`/${p(e[3],5)}`:""})`}function d(t,e){let n=[...t];for(let r=0;r<e.length;r++){let a=0;for(let o=0;o<e[0].length;o++)a+=t[o]*e[r][o];n[r]=a}return n}function p(t,e=2){let n=10**e;return Math.round(t*n)/n}function v(t){let e=`${Math.round(t[0]*255)}, ${Math.round(t[1]*255)}, ${Math.round(t[2]*255)}`;return t[3]!==1?`rgba(${e}, ${p(t[3],5)})`:`rgb(${e})`}var U=[[.2104542553,.793617785,-.0040720468],[1.9779984951,-2.428592205,.4505937099],[.0259040371,.7827717662,-.808675766]],K=[[4.0767416621,-3.3077115913,.2309699292],[-1.2684380046,2.6097574011,-.3413193965],[-.0041960863,-.7034186147,1.707614701]];var j=[[.4122214708,.5363325363,.0514459929],[.2119034982,.6806995451,.1073969566],[.0883024619,.2817188376,.6299787005]],J=[[1,.3963377774,.2158037573],[1,-.1055613458,-.0638541728],[1,-.0894841775,-1.291485548]],Q=[[3.2406,-1.5372,-.4986],[-.9689,1.8758,.0415],[.0557,-.204,1.057]];function N(t){let[e,n,r,a]=t;e=Math.abs(e%360);let o=n*(1-Math.abs(2*r-1)),l=o*(1-Math.abs(e/60%2-1)),i=0,c=0,u=0;0<=e&&e<60?(i=o,c=l):60<=e&&e<120?(i=l,c=o):120<=e&&e<180?(c=o,u=l):180<=e&&e<240?(c=l,u=o):240<=e&&e<300?(i=l,u=o):300<=e&&e<360&&(i=o,u=l);let g=r-o/2;return[i+g,c+g,u+g,a]}function W(t){let[e,n,r,a]=t,o=n===0&&r===0?0:S(Math.atan2(r,n));return[e,Math.sqrt(n**2+r**2),o<0?o+360:o,a]}function C(t){let[e,n,r,a]=t,o=q(r);return[e,n*Math.cos(o),n*Math.sin(o),a]}function e0(t){let e=Math.cbrt(t[0]),n=Math.cbrt(t[1]),r=Math.cbrt(t[2]),a=t[3];return d([e,n,r,a],U)}function t0(t){let[e,n,r,a]=d(t,K);return[Math.max(0,e),Math.max(0,n),Math.max(0,r),Math.max(0,a)]}function b(t){return t.map((e,n)=>n===3?s(e,0,1):e<=.0031308?s(e*12.92,0,1):s(1.055*e**(1/2.4)-.055,0,1))}function r0(t){return d(t,j)}function n0(t){let[e,n,r,a]=t,o=[0,0,0,a],l=n/(13*e),i=r/(13*e);return o[1]=e<=8?e*(3/29)**3:((e+16)/116)**3,o[0]=o[1]*(9/4)*l,o[2]=o[1]*((12-3*l-20*i)/4*i),o}function z(t){return b(a0(n0(t)))}function o0(t){let e=d(t,J);return[e[0]**3,e[1]**3,e[2]**3,e[3]]}function T(t){return b(t0(o0(t)))}function _(t){return T(C(t))}function M(t){return t.map((e,n)=>n===3?e:e<=.04045?e/12.92:((e+.055)/1.055)**2.4)}function x(t){return e0(r0(M(t)))}function w(t){return W(x(t))}function a0(t){return d(t,Q)}var l0={black:[0,0,0,1],silver:[.75,.75,.75,1],gray:[.5,.5,.5,1],white:[1,1,1,1],maroon:[.5,0,0,1],red:[1,0,0,1],purple:[.5,0,.5,1],fuchsia:[1,0,1,1],green:[0,.5,0,1],lime:[0,1,0,1],olive:[.5,.5,0,1],yellow:[1,1,0,1],navy:[0,0,.5,1],blue:[0,0,1,1],teal:[0,.5,.5,1],aqua:[0,1,1,1],orange:[1,.6470588235294118,0,1],aliceblue:[.9411764705882353,.9725490196078431,1,1],antiquewhite:[.9803921568627451,.9215686274509803,.8431372549019608,1],aquamarine:[.4980392156862745,1,.8313725490196079,1],azure:[.9411764705882353,1,1,1],beige:[.9607843137254902,.9607843137254902,.8627450980392157,1],bisque:[1,.8941176470588236,.7686274509803922,1],blanchedalmond:[1,.9215686274509803,.803921568627451,1],blueviolet:[.5411764705882353,.16862745098039217,.8862745098039215,1],brown:[.6470588235294118,.16470588235294117,.16470588235294117,1],burlywood:[.8705882352941177,.7215686274509804,.5294117647058824,1],cadetblue:[.37254901960784315,.6196078431372549,.6274509803921569,1],chartreuse:[.4980392156862745,1,0,1],chocolate:[.8235294117647058,.4117647058823529,.11764705882352941,1],coral:[1,.4980392156862745,.3137254901960784,1],cornflowerblue:[.39215686274509803,.5843137254901961,.9294117647058824,1],cornsilk:[1,.9725490196078431,.8627450980392157,1],crimson:[.8627450980392157,.0784313725490196,.23529411764705882,1],cyan:[0,1,1,1],darkblue:[0,0,.5450980392156862,1],darkcyan:[0,.5450980392156862,.5450980392156862,1],darkgoldenrod:[.7215686274509804,.5254901960784314,.043137254901960784,1],darkgray:[.6627450980392157,.6627450980392157,.6627450980392157,1],darkgreen:[0,.39215686274509803,0,1],darkgrey:[.6627450980392157,.6627450980392157,.6627450980392157,1],darkkhaki:[.7411764705882353,.7176470588235294,.4196078431372549,1],darkmagenta:[.5450980392156862,0,.5450980392156862,1],darkolivegreen:[.3333333333333333,.4196078431372549,.1843137254901961,1],darkorange:[1,.5490196078431373,0,1],darkorchard:[.6,.19607843137254902,.8,1],darkred:[.5450980392156862,0,0,1],darksalmon:[.9137254901960784,.5882352941176471,.47843137254901963,1],darkseagreen:[.5607843137254902,.7372549019607844,.5607843137254902,1],darkslateblue:[.2823529411764706,.23921568627450981,.5450980392156862,1],darkslategray:[.1843137254901961,.30980392156862746,.30980392156862746,1],darkslategrey:[.1843137254901961,.30980392156862746,.30980392156862746,1],darkturquoise:[.1843137254901961,.30980392156862746,.30980392156862746,1],darkviolet:[.5803921568627451,0,.8274509803921568,1],deeppink:[1,.0784313725490196,.5764705882352941,1],deepskyblue:[0,.7490196078431373,1,1],dimgray:[.4117647058823529,.4117647058823529,.4117647058823529,1],dimgrey:[.4117647058823529,.4117647058823529,.4117647058823529,1],dodgerblue:[.11764705882352941,.5647058823529412,1,1],firebrick:[.6980392156862745,.13333333333333333,.13333333333333333,1],floralwhite:[1,.9803921568627451,.9411764705882353,1],forestgreen:[.13333333333333333,.5450980392156862,.13333333333333333,1],gainsboro:[.8627450980392157,.8627450980392157,.8627450980392157,1],ghostwhite:[.9725490196078431,.9725490196078431,1,1],gold:[1,.8431372549019608,0,1],goldenrod:[.8549019607843137,.6470588235294118,.12549019607843137,1],greenyellow:[.6784313725490196,1,.1843137254901961,1],grey:[.5019607843137255,.5019607843137255,.5019607843137255,1],honeydew:[.9411764705882353,1,.9411764705882353,1],hotpink:[1,.4117647058823529,.7058823529411765,1],indianred:[.803921568627451,.3607843137254902,.3607843137254902,1],indigo:[.29411764705882354,0,.5098039215686274,1],ivory:[1,1,.9411764705882353,1],khaki:[.9411764705882353,.9019607843137255,.5490196078431373,1],lavendar:[.9019607843137255,.9019607843137255,.9803921568627451,1],lavenderblush:[1,.9411764705882353,.9607843137254902,1],lawngreen:[.48627450980392156,.9882352941176471,0,1],lemonchiffon:[1,.9803921568627451,.803921568627451,1],lightblue:[.6784313725490196,.8470588235294118,.9019607843137255,1],lightcoral:[.9411764705882353,.5019607843137255,.5019607843137255,1],lightcyan:[.8784313725490196,1,1,1],lightgoldenrodyellow:[.9803921568627451,.9803921568627451,.8235294117647058,1],lightgray:[.8274509803921568,.8274509803921568,.8274509803921568,1],lightgreen:[.5647058823529412,.9333333333333333,.5647058823529412,1],lightgrey:[.8274509803921568,.8274509803921568,.8274509803921568,1],lightpink:[1,.7137254901960784,.7568627450980392,1],lightsalmon:[1,.6274509803921569,.47843137254901963,1],lightseagreen:[.12549019607843137,.6980392156862745,.6666666666666666,1],lightskyblue:[.5294117647058824,.807843137254902,.9803921568627451,1],lightslategray:[.4666666666666667,.5333333333333333,.6,1],lightslategrey:[.4666666666666667,.5333333333333333,.6,1],lightsteelblue:[.6901960784313725,.7686274509803922,.8705882352941177,1],lightyellow:[1,1,.8784313725490196,1],limegreen:[.19607843137254902,.803921568627451,.19607843137254902,1],linen:[.9803921568627451,.9411764705882353,.9019607843137255,1],magenta:[1,0,1,1],mediumaquamarine:[.4,.803921568627451,.6666666666666666,1],mediumblue:[0,0,.803921568627451,1],mediumorchid:[.7294117647058823,.3333333333333333,.8274509803921568,1],mediumpurple:[.5764705882352941,.4392156862745098,.8588235294117647,1],mediumseagreen:[.23529411764705882,.7019607843137254,.44313725490196076,1],mediumslateblue:[.4823529411764706,.40784313725490196,.9333333333333333,1],mediumspringgreen:[0,.9803921568627451,.6039215686274509,1],mediumturquoise:[.2823529411764706,.8196078431372549,.8,1],mediumvioletred:[.7803921568627451,.08235294117647059,.5215686274509804,1],midnightblue:[.09803921568627451,.09803921568627451,.4392156862745098,1],mintcream:[.9607843137254902,1,.9803921568627451,1],mistyrose:[1,.8941176470588236,.8823529411764706,1],moccasin:[1,.8941176470588236,.7098039215686275,1],navajowhite:[1,.8705882352941177,.6784313725490196,1],oldlace:[.9921568627450981,.9607843137254902,.9019607843137255,1],olivedrab:[.4196078431372549,.5568627450980392,.13725490196078433,1],orangered:[1,.27058823529411763,0,1],orchid:[.8549019607843137,.4392156862745098,.8392156862745098,1],palegoldenrod:[.9333333333333333,.9098039215686274,.6666666666666666,1],palegreen:[.596078431372549,.984313725490196,.596078431372549,1],paleturquoise:[.6862745098039216,.9333333333333333,.9333333333333333,1],palevioletred:[.8588235294117647,.4392156862745098,.5764705882352941,1],papayawhip:[1,.9372549019607843,.8352941176470589,1],peachpuff:[1,.8549019607843137,.7254901960784313,1],peru:[.803921568627451,.5215686274509804,.24705882352941178,1],pink:[1,.7529411764705882,.796078431372549,1],plum:[.8666666666666667,.6274509803921569,.8666666666666667,1],powderblue:[.6901960784313725,.8784313725490196,.9019607843137255,1],rosybrown:[.7372549019607844,.5607843137254902,.5607843137254902,1],royalblue:[.2549019607843137,.4117647058823529,.8823529411764706,1],saddlebrown:[.5450980392156862,.27058823529411763,.07450980392156863,1],salmon:[.9803921568627451,.5019607843137255,.4470588235294118,1],sandybrown:[.9568627450980393,.6431372549019608,.3764705882352941,1],seagreen:[.1803921568627451,.5450980392156862,.3411764705882353,1],seashell:[1,.9607843137254902,.9333333333333333,1],sienna:[.6274509803921569,.3215686274509804,.17647058823529413,1],skyblue:[.5294117647058824,.807843137254902,.9215686274509803,1],slateblue:[.41568627450980394,.35294117647058826,.803921568627451,1],slategray:[.4392156862745098,.5019607843137255,.5647058823529412,1],slategrey:[.4392156862745098,.5019607843137255,.5647058823529412,1],snow:[1,.9803921568627451,.9803921568627451,1],springgreen:[0,1,.4980392156862745,1],steelblue:[.27450980392156865,.5098039215686274,.7058823529411765,1],tan:[.8235294117647058,.7058823529411765,.5490196078431373,1],thistle:[.8470588235294118,.7490196078431373,.8470588235294118,1],tomato:[1,.38823529411764707,.2784313725490196,1],turquoise:[.25098039215686274,.8784313725490196,.8156862745098039,1],violet:[.9333333333333333,.5098039215686274,.9333333333333333,1],wheat:[.9607843137254902,.8705882352941177,.7019607843137254,1],whitesmoke:[.9607843137254902,.9607843137254902,.9607843137254902,1],yellowgreen:[.6039215686274509,.803921568627451,.19607843137254902,1],rebeccapurple:[.4,.2,.6,1]},A=l0;var s0=/-?[0-9.]+%?/g,i0=/^#?[0-9a-f]{3,8}$/i,u0=16**6,F=16**4,I=16**2;function h(t){let e=h0(t),n={get hex(){let r="#";return r+=m(Math.round(e[0]*255).toString(16),2),r+=m(Math.round(e[1]*255).toString(16),2),r+=m(Math.round(e[2]*255).toString(16),2),e[3]<1&&(r+=m(Math.round(e[3]*255).toString(16),2)),r},get hexVal(){e[3]<1&&console.warn(`hexVal converted a semi-transparent color (${e[3]*100}%) to fully opaque`);let r=Math.round(e[0]*255),a=Math.round(e[1]*255),o=Math.round(e[2]*255);return r*F+a*I+o},get rgb(){return v(e)},rgbVal:e,get rgba(){return v(e)},rgbaVal:e,get linearRGB(){return M(e)},get p3(){return G("display-p3",e)},p3Val:e,get oklab(){return G("oklab",x(e))},get oklabVal(){return x(e)},get oklch(){return G("oklch",w(e))},get oklchVal(){return w(e)}};return n.toString=()=>n.hex,n}function c0(t){if(t>u0)throw new Error("better-color-tools can\u2019t parse hex numbers with alpha (0x0000000 is indistinguishable from 0x00000000). Please use hex string, or another color method");let e=t,n=Math.floor(e/F);e-=n*F;let r=Math.floor(e/I);e-=r*I;let a=e;return[n/255,r/255,a/255,1]}function f(t,e){let n=t.match(s0);if(!n)throw new Error(`Unexpected color format: ${t}`);let r=[0,0,0,1];return n.forEach((a,o)=>{a.includes("%")?r[o]=parseFloat(a)/100:e[o]===1/0?r[o]=parseFloat(a):r[o]=parseFloat(a)/(e[o]||1)}),r}function h0(t){if(Array.isArray(t)){if(t.some(e=>typeof e!="number"))throw new Error(`Color array must be numbers, received ${t}`);if(t.length<3||t.length>4)throw new Error(`Expected [R, G, B, A?], received ${t}`);return[s(t[0],0,1),s(t[1],0,1),s(t[2],0,1),typeof t[3]=="number"?s(t[3],0,1):1]}if(typeof t=="number")return c0(t);if(typeof t=="string"){let e=t.trim();if(!e)throw new Error("Expected color, received empty string");if(A[e.toLowerCase()])return A[e.toLowerCase()];if(i0.test(e)){let a=e.replace("#",""),o=[0,0,0,1];if(a.length>=6)for(let l=0;l<a.length/2;l++){let i=l*2,c=i+2,u=a.substring(i,c);o[l]=parseInt(u,16)/255}else for(let l=0;l<a.length;l++){let i=a.charAt(l);o[l]=parseInt(`${i}${i}`,16)/255}return o}let[n,r]=e.split("(");if(n==="color"){let a=r.indexOf(" ");n=r.substring(0,a),r=r.substring(a)}switch(n){case"rgb":case"rgba":case"srgb":{let[a,o,l,i]=f(r,[255,255,255,1]);return[s(a,0,1),s(o,0,1),s(l,0,1),s(i,0,1)]}case"srgb-linear":{let[a,o,l,i]=f(r,[255,255,255,1]);return b([s(a,0,1),s(o,0,1),s(l,0,1),s(i,0,1)])}case"hsl":{let[a,o,l,i]=f(r,[1/0,1,1,1]);return N([a,s(o,0,1),s(l,0,1),s(i,0,1)])}case"p3":case"display-p3":{let[a,o,l,i]=f(r,[1,1,1,1]);return[s(a,0,1),s(o,0,1),s(l,0,1),s(i,0,1)]}case"luv":return z(f(r,[1,1,1,1]));case"oklab":return T(f(r,[1,1,1,1]));case"oklch":return _(f(r,[1,1,1/0,1]))}}throw new Error(`Unable to parse color "${t}"`)}function V(t){return p(h(t).oklabVal[0],5)}function k(t,e,n=.5,r="oklab"){let a=s(n,0,1);if(n===0)return h(t);if(n===1)return h(e);let o=1-a,l=a,i={oklch:w,oklab:x,linearRGB:M,sRGB:E=>E},c={oklch:_,oklab:T,linearRGB:b,sRGB:E=>E},u=i[r],g=c[r];if(!u)throw new Error(`Unknown color space "${r}", try "oklab", "oklch", "linearRGB", or "sRGB"`);let R=h(t).rgbVal,y=h(e).rgbVal;r==="oklch"&&(R[0]===R[1]&&R[1]===R[2]||y[0]===y[1]&&y[1]===y[2])&&(u=i.oklab,g=c.oklab);let[P,X,L,D]=u(R),[Y,Z,B,H]=u(y);return r==="oklch"&&Math.abs(B-L)>180&&(Math.max(L,B)===B?B-=360:L-=360),h(g([P*o+Y*l,X*o+Z*l,L*o+B*l,D*o+H*l]))}function $(t,e,n="oklab"){let r=s(e,-1,1);return r>=0?k(t,"black",r,n):O(t,-r)}function O(t,e,n="oklab"){let r=s(e,-1,1);return r>=0?k(t,"white",r,n):$(t,-r)}var $0={darken:$,from:h,lighten:O,lightness:V,mix:k};export{s as clamp,G as colorFn,$ as darken,$0 as default,h as from,m as leftPad,O as lighten,V as lightness,k as mix,v as rgbFn,p as round}; | ||
function x(t,e=2){let o=t;for(;o.length<e;)o=`0${o}`;return o}function P(t){return t*(Math.PI/180)}function X(t){return t*(180/Math.PI)}function s(t,e,o){return Math.min(Math.max(t,e),o)}function m(t,e){return`color(${t} ${f(e[0],5)} ${f(e[1],5)} ${f(e[2],5)}${e[3]<1?`/${f(e[3],5)}`:""})`}function b(t,e){let o=[...t];for(let r=0;r<e.length;r++){let a=0;for(let n=0;n<e[0].length;n++)a+=t[n]*e[r][n];o[r]=a}return o}function f(t,e=2){let o=10**e;return Math.round(t*o)/o}function L(t){let e=`${Math.round(t[0]*255)}, ${Math.round(t[1]*255)}, ${Math.round(t[2]*255)}`;return t[3]!==1?`rgba(${e}, ${f(t[3],5)})`:`rgb(${e})`}var U=216/24389,I=24389/27,M=[95.47,100,108.33],Y=M[0]+15*M[1]+3*M[2],Z=4*M[0]/Y,H=9*M[1]/Y,r0=[[.2104542553,.793617785,-.0040720468],[1.9779984951,-2.428592205,.4505937099],[.0259040371,.7827717662,-.808675766]],o0=[[4.0767416621,-3.3077115913,.2309699292],[-1.2684380046,2.6097574011,-.3413193965],[-.0041960863,-.7034186147,1.707614701]],n0=[[.4124,.3576,.1805],[.2126,.7152,.0722],[.0193,.1192,.9505]],a0=[[.4122214708,.5363325363,.0514459929],[.2119034982,.6806995451,.1073969566],[.0883024619,.2817188376,.6299787005]],l0=[[1,.3963377774,.2158037573],[1,-.1055613458,-.0638541728],[1,-.0894841775,-1.291485548]],s0=[[3.2406,-1.5372,-.4986],[-.9689,1.8758,.0415],[.0557,-.204,1.057]];function K(t){let[e,o,r,a]=t;e=Math.abs(e%360);let n=o*(1-Math.abs(2*r-1)),l=n*(1-Math.abs(e/60%2-1)),i=0,u=0,c=0;0<=e&&e<60?(i=n,u=l):60<=e&&e<120?(i=l,u=n):120<=e&&e<180?(u=n,c=l):180<=e&&e<240?(u=l,c=n):240<=e&&e<300?(i=l,c=n):300<=e&&e<360&&(i=n,c=l);let h=r-n/2;return[i+h,u+h,c+h,a]}function i0(t){let[e,o,r,a]=t,n=o===0&&r===0?0:X(Math.atan2(r,o));return[e,Math.sqrt(o**2+r**2),n<0?n+360:n,a]}function u0(t){let[e,o,r,a]=t,n=P(r);return[e,o*Math.cos(n),o*Math.sin(n),a]}function c0(t){let e=Math.cbrt(t[0]),o=Math.cbrt(t[1]),r=Math.cbrt(t[2]),a=t[3];return b([e,o,r,a],r0)}function h0(t){let[e,o,r,a]=b(t,o0);return[Math.max(0,e),Math.max(0,o),Math.max(0,r),Math.max(0,a)]}function k(t){return t.map((e,o)=>o===3?s(e,0,1):e<=.0031308?s(e*12.92,0,1):s(1.055*Math.pow(e,1/2.4)-.055,0,1))}function p0(t){return b(t,a0)}function f0(t){let[e,o,r,a]=t;e*=100,o*=100,r*=100;let n=e>U*I?((e+16)/116)**3:e/I,l=(52*e/(o+13*e*Z)-1)/3||0,i=-5*n||0,u=-1/3,h=((n*(39*e/(r+13*e*H)-5)||0)-i)/(l-u)||0,d=h*l+i;return[h,n,d,a]}function j(t){return z(f0(t))}function g0(t){let e=b(t,l0);return[e[0]**3,e[1]**3,e[2]**3,e[3]]}function w(t){return k(h0(g0(t)))}function E(t){return w(u0(t))}function R(t){return t.map((e,o)=>o===3?e:e<=.04045?e/12.92:((e+.055)/1.055)**2.4)}function F(t){return d0(O(t))}function y(t){return c0(p0(R(t)))}function _(t){return i0(y(t))}function O(t){return b(R(t),n0)}function z(t){return k(b(t,s0))}function d0(t){let[e,o,r,a]=t,n=e+15*o+3*r,l=4*e/n||0,i=9*o/n||0,u=e>U?116*Math.pow(o,1/3)-16:I*o,c=13*u*(l-Z)||0,h=13*u*(i-H)||0;return[u/100,c/100,h/100,a]}var m0={black:[0,0,0,1],silver:[.75,.75,.75,1],gray:[.5,.5,.5,1],white:[1,1,1,1],maroon:[.5,0,0,1],red:[1,0,0,1],purple:[.5,0,.5,1],fuchsia:[1,0,1,1],green:[0,.5,0,1],lime:[0,1,0,1],olive:[.5,.5,0,1],yellow:[1,1,0,1],navy:[0,0,.5,1],blue:[0,0,1,1],teal:[0,.5,.5,1],aqua:[0,1,1,1],orange:[1,.6470588235294118,0,1],aliceblue:[.9411764705882353,.9725490196078431,1,1],antiquewhite:[.9803921568627451,.9215686274509803,.8431372549019608,1],aquamarine:[.4980392156862745,1,.8313725490196079,1],azure:[.9411764705882353,1,1,1],beige:[.9607843137254902,.9607843137254902,.8627450980392157,1],bisque:[1,.8941176470588236,.7686274509803922,1],blanchedalmond:[1,.9215686274509803,.803921568627451,1],blueviolet:[.5411764705882353,.16862745098039217,.8862745098039215,1],brown:[.6470588235294118,.16470588235294117,.16470588235294117,1],burlywood:[.8705882352941177,.7215686274509804,.5294117647058824,1],cadetblue:[.37254901960784315,.6196078431372549,.6274509803921569,1],chartreuse:[.4980392156862745,1,0,1],chocolate:[.8235294117647058,.4117647058823529,.11764705882352941,1],coral:[1,.4980392156862745,.3137254901960784,1],cornflowerblue:[.39215686274509803,.5843137254901961,.9294117647058824,1],cornsilk:[1,.9725490196078431,.8627450980392157,1],crimson:[.8627450980392157,.0784313725490196,.23529411764705882,1],cyan:[0,1,1,1],darkblue:[0,0,.5450980392156862,1],darkcyan:[0,.5450980392156862,.5450980392156862,1],darkgoldenrod:[.7215686274509804,.5254901960784314,.043137254901960784,1],darkgray:[.6627450980392157,.6627450980392157,.6627450980392157,1],darkgreen:[0,.39215686274509803,0,1],darkgrey:[.6627450980392157,.6627450980392157,.6627450980392157,1],darkkhaki:[.7411764705882353,.7176470588235294,.4196078431372549,1],darkmagenta:[.5450980392156862,0,.5450980392156862,1],darkolivegreen:[.3333333333333333,.4196078431372549,.1843137254901961,1],darkorange:[1,.5490196078431373,0,1],darkorchard:[.6,.19607843137254902,.8,1],darkred:[.5450980392156862,0,0,1],darksalmon:[.9137254901960784,.5882352941176471,.47843137254901963,1],darkseagreen:[.5607843137254902,.7372549019607844,.5607843137254902,1],darkslateblue:[.2823529411764706,.23921568627450981,.5450980392156862,1],darkslategray:[.1843137254901961,.30980392156862746,.30980392156862746,1],darkslategrey:[.1843137254901961,.30980392156862746,.30980392156862746,1],darkturquoise:[.1843137254901961,.30980392156862746,.30980392156862746,1],darkviolet:[.5803921568627451,0,.8274509803921568,1],deeppink:[1,.0784313725490196,.5764705882352941,1],deepskyblue:[0,.7490196078431373,1,1],dimgray:[.4117647058823529,.4117647058823529,.4117647058823529,1],dimgrey:[.4117647058823529,.4117647058823529,.4117647058823529,1],dodgerblue:[.11764705882352941,.5647058823529412,1,1],firebrick:[.6980392156862745,.13333333333333333,.13333333333333333,1],floralwhite:[1,.9803921568627451,.9411764705882353,1],forestgreen:[.13333333333333333,.5450980392156862,.13333333333333333,1],gainsboro:[.8627450980392157,.8627450980392157,.8627450980392157,1],ghostwhite:[.9725490196078431,.9725490196078431,1,1],gold:[1,.8431372549019608,0,1],goldenrod:[.8549019607843137,.6470588235294118,.12549019607843137,1],greenyellow:[.6784313725490196,1,.1843137254901961,1],grey:[.5019607843137255,.5019607843137255,.5019607843137255,1],honeydew:[.9411764705882353,1,.9411764705882353,1],hotpink:[1,.4117647058823529,.7058823529411765,1],indianred:[.803921568627451,.3607843137254902,.3607843137254902,1],indigo:[.29411764705882354,0,.5098039215686274,1],ivory:[1,1,.9411764705882353,1],khaki:[.9411764705882353,.9019607843137255,.5490196078431373,1],lavendar:[.9019607843137255,.9019607843137255,.9803921568627451,1],lavenderblush:[1,.9411764705882353,.9607843137254902,1],lawngreen:[.48627450980392156,.9882352941176471,0,1],lemonchiffon:[1,.9803921568627451,.803921568627451,1],lightblue:[.6784313725490196,.8470588235294118,.9019607843137255,1],lightcoral:[.9411764705882353,.5019607843137255,.5019607843137255,1],lightcyan:[.8784313725490196,1,1,1],lightgoldenrodyellow:[.9803921568627451,.9803921568627451,.8235294117647058,1],lightgray:[.8274509803921568,.8274509803921568,.8274509803921568,1],lightgreen:[.5647058823529412,.9333333333333333,.5647058823529412,1],lightgrey:[.8274509803921568,.8274509803921568,.8274509803921568,1],lightpink:[1,.7137254901960784,.7568627450980392,1],lightsalmon:[1,.6274509803921569,.47843137254901963,1],lightseagreen:[.12549019607843137,.6980392156862745,.6666666666666666,1],lightskyblue:[.5294117647058824,.807843137254902,.9803921568627451,1],lightslategray:[.4666666666666667,.5333333333333333,.6,1],lightslategrey:[.4666666666666667,.5333333333333333,.6,1],lightsteelblue:[.6901960784313725,.7686274509803922,.8705882352941177,1],lightyellow:[1,1,.8784313725490196,1],limegreen:[.19607843137254902,.803921568627451,.19607843137254902,1],linen:[.9803921568627451,.9411764705882353,.9019607843137255,1],magenta:[1,0,1,1],mediumaquamarine:[.4,.803921568627451,.6666666666666666,1],mediumblue:[0,0,.803921568627451,1],mediumorchid:[.7294117647058823,.3333333333333333,.8274509803921568,1],mediumpurple:[.5764705882352941,.4392156862745098,.8588235294117647,1],mediumseagreen:[.23529411764705882,.7019607843137254,.44313725490196076,1],mediumslateblue:[.4823529411764706,.40784313725490196,.9333333333333333,1],mediumspringgreen:[0,.9803921568627451,.6039215686274509,1],mediumturquoise:[.2823529411764706,.8196078431372549,.8,1],mediumvioletred:[.7803921568627451,.08235294117647059,.5215686274509804,1],midnightblue:[.09803921568627451,.09803921568627451,.4392156862745098,1],mintcream:[.9607843137254902,1,.9803921568627451,1],mistyrose:[1,.8941176470588236,.8823529411764706,1],moccasin:[1,.8941176470588236,.7098039215686275,1],navajowhite:[1,.8705882352941177,.6784313725490196,1],oldlace:[.9921568627450981,.9607843137254902,.9019607843137255,1],olivedrab:[.4196078431372549,.5568627450980392,.13725490196078433,1],orangered:[1,.27058823529411763,0,1],orchid:[.8549019607843137,.4392156862745098,.8392156862745098,1],palegoldenrod:[.9333333333333333,.9098039215686274,.6666666666666666,1],palegreen:[.596078431372549,.984313725490196,.596078431372549,1],paleturquoise:[.6862745098039216,.9333333333333333,.9333333333333333,1],palevioletred:[.8588235294117647,.4392156862745098,.5764705882352941,1],papayawhip:[1,.9372549019607843,.8352941176470589,1],peachpuff:[1,.8549019607843137,.7254901960784313,1],peru:[.803921568627451,.5215686274509804,.24705882352941178,1],pink:[1,.7529411764705882,.796078431372549,1],plum:[.8666666666666667,.6274509803921569,.8666666666666667,1],powderblue:[.6901960784313725,.8784313725490196,.9019607843137255,1],rosybrown:[.7372549019607844,.5607843137254902,.5607843137254902,1],royalblue:[.2549019607843137,.4117647058823529,.8823529411764706,1],saddlebrown:[.5450980392156862,.27058823529411763,.07450980392156863,1],salmon:[.9803921568627451,.5019607843137255,.4470588235294118,1],sandybrown:[.9568627450980393,.6431372549019608,.3764705882352941,1],seagreen:[.1803921568627451,.5450980392156862,.3411764705882353,1],seashell:[1,.9607843137254902,.9333333333333333,1],sienna:[.6274509803921569,.3215686274509804,.17647058823529413,1],skyblue:[.5294117647058824,.807843137254902,.9215686274509803,1],slateblue:[.41568627450980394,.35294117647058826,.803921568627451,1],slategray:[.4392156862745098,.5019607843137255,.5647058823529412,1],slategrey:[.4392156862745098,.5019607843137255,.5647058823529412,1],snow:[1,.9803921568627451,.9803921568627451,1],springgreen:[0,1,.4980392156862745,1],steelblue:[.27450980392156865,.5098039215686274,.7058823529411765,1],tan:[.8235294117647058,.7058823529411765,.5490196078431373,1],thistle:[.8470588235294118,.7490196078431373,.8470588235294118,1],tomato:[1,.38823529411764707,.2784313725490196,1],turquoise:[.25098039215686274,.8784313725490196,.8156862745098039,1],violet:[.9333333333333333,.5098039215686274,.9333333333333333,1],wheat:[.9607843137254902,.8705882352941177,.7019607843137254,1],whitesmoke:[.9607843137254902,.9607843137254902,.9607843137254902,1],yellowgreen:[.6039215686274509,.803921568627451,.19607843137254902,1],rebeccapurple:[.4,.2,.6,1]},q=m0;var b0=/-?[0-9.]+%?/g,x0=/^#?[0-9a-f]{3,8}$/i,k0=16**6,N=16**4,S=16**2;function p(t){let e=y0(t),o={get hex(){let r="#";return r+=x(Math.round(e[0]*255).toString(16),2),r+=x(Math.round(e[1]*255).toString(16),2),r+=x(Math.round(e[2]*255).toString(16),2),e[3]<1&&(r+=x(Math.round(e[3]*255).toString(16),2)),r},get hexVal(){e[3]<1&&console.warn(`hexVal converted a semi-transparent color (${e[3]*100}%) to fully opaque`);let r=Math.round(e[0]*255),a=Math.round(e[1]*255),n=Math.round(e[2]*255);return r*N+a*S+n},get luv(){return m("luv",F(e))},get luvVal(){return F(e)},get rgb(){return L(e)},rgbVal:e,get rgba(){return L(e)},rgbaVal:e,get linearRGB(){return R(e)},get p3(){return m("display-p3",e)},p3Val:e,get oklab(){return m("oklab",y(e))},get oklabVal(){return y(e)},get oklch(){return m("oklch",_(e))},get oklchVal(){return _(e)},get xyz(){return m("xyz-d65",O(e))},get xyzVal(){return O(e)}};return o.toString=()=>o.hex,o}function R0(t){if(t>k0)throw new Error("better-color-tools can\u2019t parse hex numbers with alpha (0x0000000 is indistinguishable from 0x00000000). Please use hex string, or another color method");let e=t,o=Math.floor(e/N);e-=o*N;let r=Math.floor(e/S);e-=r*S;let a=e;return[o/255,r/255,a/255,1]}function g(t,e){let o=t.match(b0);if(!o)throw new Error(`Unexpected color format: ${t}`);let r=[0,0,0,1];return o.forEach((a,n)=>{a.includes("%")?r[n]=parseFloat(a)/100:e[n]===1/0?r[n]=parseFloat(a):r[n]=parseFloat(a)/(e[n]||1)}),r}function y0(t){if(Array.isArray(t)){if(t.some(e=>typeof e!="number"))throw new Error(`Color array must be numbers, received ${t}`);if(t.length<3||t.length>4)throw new Error(`Expected [R, G, B, A?], received ${t}`);return[s(t[0],0,1),s(t[1],0,1),s(t[2],0,1),typeof t[3]=="number"?s(t[3],0,1):1]}if(typeof t=="number")return R0(t);if(typeof t=="string"){let e=t.trim();if(!e)throw new Error("Expected color, received empty string");if(q[e.toLowerCase()])return q[e.toLowerCase()];if(x0.test(e)){let a=e.replace("#",""),n=[0,0,0,1];if(a.length>=6)for(let l=0;l<a.length/2;l++){let i=l*2,u=i+2,c=a.substring(i,u);n[l]=parseInt(c,16)/255}else for(let l=0;l<a.length;l++){let i=a.charAt(l);n[l]=parseInt(`${i}${i}`,16)/255}return n}let[o,r]=e.split("(");if(o==="color"){let a=r.indexOf(" ");o=r.substring(0,a),r=r.substring(a)}switch(o){case"rgb":case"rgba":case"srgb":{let[a,n,l,i]=g(r,[255,255,255,1]);return[s(a,0,1),s(n,0,1),s(l,0,1),s(i,0,1)]}case"srgb-linear":{let[a,n,l,i]=g(r,[255,255,255,1]);return k([s(a,0,1),s(n,0,1),s(l,0,1),s(i,0,1)])}case"hsl":{let[a,n,l,i]=g(r,[1/0,1,1,1]);return K([a,s(n,0,1),s(l,0,1),s(i,0,1)])}case"p3":case"display-p3":{let[a,n,l,i]=g(r,[1,1,1,1]);return[s(a,0,1),s(n,0,1),s(l,0,1),s(i,0,1)]}case"luv":{let a=g(r,[1,1,1,1]);return j(a)}case"oklab":return w(g(r,[1,1,1,1]));case"oklch":return E(g(r,[1,1,1/0,1]));case"xyz":case"xyz-d65":return z(g(r,[1,1,1,1]))}}throw new Error(`Unable to parse color "${t}"`)}function D(t){return f(p(t).oklabVal[0],5)}function B(t,e,o=.5,r="oklab"){let a=s(o,0,1);if(o===0)return p(t);if(o===1)return p(e);let n=1-a,l=a,i={oklch:_,oklab:y,linearRGB:R,sRGB:V=>V},u={oklch:E,oklab:w,linearRGB:k,sRGB:V=>V},c=i[r],h=u[r];if(!c)throw new Error(`Unknown color space "${r}", try "oklab", "oklch", "linearRGB", or "sRGB"`);let d=p(t).rgbVal,G=p(e).rgbVal;r==="oklch"&&(d[0]===d[1]&&d[1]===d[2]||G[0]===G[1]&&G[1]===G[2])&&(c=i.oklab,h=u.oklab);let[W,J,v,Q]=c(d),[C,e0,T,t0]=c(G);return r==="oklch"&&Math.abs(T-v)>180&&(Math.max(v,T)===T?T-=360:v-=360),p(h([W*n+C*l,J*n+e0*l,v*n+T*l,Q*n+t0*l]))}function $(t,e,o="oklab"){let r=s(e,-1,1);return r>=0?B(t,"black",r,o):A(t,-r)}function A(t,e,o="oklab"){let r=s(e,-1,1);return r>=0?B(t,"white",r,o):$(t,-r)}var D0={darken:$,from:p,lighten:A,lightness:D,mix:B};export{s as clamp,m as colorFn,$ as darken,D0 as default,p as from,x as leftPad,A as lighten,D as lightness,B as mix,L as rgbFn,f as round}; |
@@ -1,2 +0,2 @@ | ||
import type { Color, LinearRGB, Oklab, Oklch, sRGB } from './colorspace.js'; | ||
import { Color, LinearRGB, LUV, Oklab, Oklch, sRGB, XYZ_D65 } from './colorspace.js'; | ||
export interface ColorOutput { | ||
@@ -18,3 +18,5 @@ /** `#000000` */ | ||
/** `color(luv 0 0 0/1)` */ | ||
luv: string; | ||
/** [L, u, v, alpha] */ | ||
luvVal: LUV; | ||
/** `color(display-p3 0 0 0/1)` */ | ||
@@ -32,2 +34,6 @@ p3: string; | ||
oklchVal: Oklch; | ||
/** `color(xyz 0 0 0/1)` (2•, D65 whitepoint) */ | ||
xyz: string; | ||
/** [X, Y, Z, alpha] (2•, D65 whitespace) */ | ||
xyzVal: XYZ_D65; | ||
toString(): string; | ||
@@ -34,0 +40,0 @@ } |
@@ -1,2 +0,3 @@ | ||
import { hslTosRGB, linearRGBTosRGB, luvTosRGB, oklabTosRGB, oklchTosRGB, sRGBToLinearRGB, sRGBToOklab, sRGBToOklch } from './colorspace.js'; | ||
import { sRGBToXYZ, xyzTosRGB } from './colorspace.js'; | ||
import { hslTosRGB, linearRGBTosRGB, luvTosRGB, oklabTosRGB, oklchTosRGB, sRGBToLinearRGB, sRGBToLuv, sRGBToOklab, sRGBToOklch } from './colorspace.js'; | ||
import cssNames from './css-names.js'; | ||
@@ -38,3 +39,3 @@ import { clamp, colorFn, leftPad, rgbFn, round } from './utils.js'; | ||
if (color[3] < 1) | ||
console.warn(`hexVal converted a semi-transparent color (${color[3] * 100}%) to fully opaque`); | ||
console.warn(`hexVal converted a semi-transparent color (${color[3] * 100}%) to fully opaque`); // eslint-disable-line no-console | ||
const r = Math.round(color[0] * 255); | ||
@@ -45,8 +46,8 @@ const g = Math.round(color[1] * 255); | ||
}, | ||
// get luv(): string { | ||
// return colorFn('luv', sRGBToLuv(color)); | ||
// }, | ||
// get luvVal(): LUV { | ||
// return sRGBToLuv(color); | ||
// }, | ||
get luv() { | ||
return colorFn('luv', sRGBToLuv(color)); | ||
}, | ||
get luvVal() { | ||
return sRGBToLuv(color); | ||
}, | ||
get rgb() { | ||
@@ -79,2 +80,8 @@ return rgbFn(color); | ||
}, | ||
get xyz() { | ||
return colorFn('xyz-d65', sRGBToXYZ(color)); | ||
}, | ||
get xyzVal() { | ||
return sRGBToXYZ(color); | ||
}, | ||
}; | ||
@@ -145,3 +152,2 @@ // JS helper | ||
// named color | ||
// console.log({ val: strVal, name: (cssNames as any)[strVal] }); | ||
if (cssNames[strVal.toLowerCase()]) { | ||
@@ -200,3 +206,4 @@ return cssNames[strVal.toLowerCase()]; | ||
case 'luv': { | ||
return luvTosRGB(parseValueStr(valueStr, [1, 1, 1, 1])); | ||
const luv = parseValueStr(valueStr, [1, 1, 1, 1]); | ||
return luvTosRGB(luv); | ||
} | ||
@@ -209,2 +216,6 @@ case 'oklab': { | ||
} | ||
case 'xyz': | ||
case 'xyz-d65': { | ||
return xyzTosRGB(parseValueStr(valueStr, [1, 1, 1, 1])); | ||
} | ||
} | ||
@@ -211,0 +222,0 @@ } |
@@ -9,4 +9,4 @@ # FAQ | ||
I started this library because I frequently need to mix colors, but was constantly disappointed at how bad the results were using common tools available (see examples above; if you’ve found a tool you’re happy with, more power to you, but I never did). I | ||
had avoided using any libraries or tools for this reason for my entire career, and instead always mixed color manually in graphics programs (in full disclosure I have a fine arts degree with a concentration in painting, which helps explain why I felt most | ||
color tools were primitive and unusable). But over time, I had this growing feeling that others had dealt with this problem and had been similarly disappointed, and that there were solutions available; they just were just unknown to the authors making | ||
had avoided using any libraries or tools for this reason for my entire career, and instead always mixed color manually in graphics programs (I have a fine arts degree with a concentration in painting, so I have to feel grumpy about colors to convince | ||
myself my art degree was worth something). But over time, I had this growing feeling that others had dealt with this problem and had been similarly disappointed, and that there were solutions available; they just were just unknown to the authors making | ||
simple color functions (including the Sass authors). After all, most programmers aren’t color scientists. And so this library is the product of finding solutions to the (deceptively-complex) problem of color mixing that aren’t god-awful, and are at least | ||
@@ -13,0 +13,0 @@ as good as I can achieve mixing colors manually if not better. |
{ | ||
"name": "better-color-tools", | ||
"description": "Better color manipulation for Sass and JavaScript / TypeScript.", | ||
"version": "0.6.3", | ||
"version": "0.7.0", | ||
"author": { | ||
@@ -29,19 +29,20 @@ "name": "Drew Powers", | ||
"devDependencies": { | ||
"@changesets/cli": "^2.21.1", | ||
"@types/node": "^16.11.26", | ||
"@typescript-eslint/eslint-plugin": "^5.14.0", | ||
"@typescript-eslint/parser": "^5.14.0", | ||
"@changesets/cli": "^2.22.0", | ||
"@types/node": "^17.0.36", | ||
"@typescript-eslint/eslint-plugin": "^5.27.0", | ||
"@typescript-eslint/parser": "^5.27.0", | ||
"chai": "^4.3.6", | ||
"esbuild": "^0.14.25", | ||
"eslint": "^8.10.0", | ||
"del-cli": "^4.0.1", | ||
"esbuild": "^0.14.42", | ||
"eslint": "^8.16.0", | ||
"eslint-config-prettier": "^8.5.0", | ||
"eslint-plugin-prettier": "^4.0.0", | ||
"mocha": "^9.2.1", | ||
"mocha": "^10.0.0", | ||
"npm-run-all": "^4.1.5", | ||
"prettier": "^2.5.1", | ||
"sass": "^1.49.9", | ||
"typescript": "^4.6.2" | ||
"prettier": "^2.6.2", | ||
"sass": "^1.52.1", | ||
"typescript": "^4.7.2" | ||
}, | ||
"scripts": { | ||
"build": "rm -rf dist && tsc && npm run bundle && cp dist/index.min.js www/src/lib/better.min.js", | ||
"build": "del dist && tsc && npm run bundle && cp dist/index.min.js www/src/lib/better.min.js", | ||
"bundle": "esbuild dist/index.js --bundle --minify --outfile=dist/index.min.js --format=esm", | ||
@@ -53,4 +54,3 @@ "changeset": "changeset", | ||
"test:benchmark": "mocha" | ||
}, | ||
"readme": "# better-color-tools\n\nColor parser and better color manipulation through **the power of science!** 🧪 Uses [Oklab](https://bottosson.github.io/posts/oklab/)/Oklch for better color operations.\n\nThe JS version of this libray is fast (`> 220k` ops/s), lightweight (`4.5 kB` gzip), and dependency-free. The Sass version… is Sass (which has no runtime).\n\n👉 **Playground**: https://better-color-tools.pages.dev/\n\n## Usage\n\n```\nnpm install better-color-tools\n```\n\n### JavaScript\n\nWorks in the browser (ESM) and Node (14+).\n\n```js\nimport better from 'better-color-utils';\n```\n\n#### Quick guide\n\n| Code | Description |\n| :-------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `better.from('red')` | Parse any valid CSS color (including [color()][css-color]) |\n| `better.from('red').[colorspace]` | Convert color to [another colorspace](#supported-colorspaces) |\n| `better.mix('red', 'lime', 0.35)` | Mix `red` and `lime` 35%, i.e. more red. Uses Oklab for better color mixing. |\n| `better.lighten('red', 0.5)` | Lighten color by 50%, i.e. halfway to white (100% is white; 0% is original color). Better than Sass’ builtin. |\n| `better.darken('red', 0.5)` | Darken color by 50%, i.e. halfway to black (100% is black; 0% is original color). Better than Sass’ builtin. |\n| `better.lightness('red', 0.5)` | Get the human-perceived value of lightness from `0` (pure black) to `1` (pure white). Alias for `better.from().oklabVal`’s lightness (first value) |\n\n#### Supported colorspaces\n\n| Colorspace | Type | Example |\n| :---------- | :--------- | :------------------------------------------------- |\n| `.hex` | `string` | `'#ff0000'` |\n| `.hexVal` | `number` | `0xff0000` |\n| `.rgb` | `string` | `'rgb(255, 0, 0)'` |\n| `.rgbVal` | `number[]` | `[1, 0, 0, 1]` (R, G, B, alpha) |\n| `.p3` | `string` | `'color(display-p3 1 0 0)'` |\n| `.p3Val` | `number[]` | (alias for `rgbVal`) |\n| `.oklab` | `string` | `'color(oklab 0.62796 0.22486 0.12585)'` |\n| `.oklabVal` | `number[]` | `[0.62796, 0.22486, 0.12585, 1]` (L, a, b, alpha) |\n| `.oklch` | `string` | `'color(oklch 0.62796 0.25768 29.23389)'` |\n| `.oklchVal` | `number[]` | `[0.62796, 0.25768, 29.23389, 1]` (L, C, h, alpha) |\n\n### Sass\n\nWorks with any version of [Dart Sass](https://sass-lang.com/dart-sass) (the current version).\n\n```scss\n@use 'better-color-tools' as better;\n```\n\n#### Quick guide\n\n| Code | Description |\n| :-------------------------------------------------------------- | ------------------------------------------------------------------------------------- |\n| `better.p3(#f00)` | Convert RGB color to [P3][p3] (`color(display-p3 …)`) ([CSS Module 5][css-color]) |\n| `better.rgbToOklab(#f00)` | Convert RGB to Oklab `color(oklab …)` ([CSS Module 5][css-color]) |\n| `better.oklabToRGB(('l': 0.87421, 'a': -0.19121, 'b': 0.1174))` | Convert Oklab map of `l`, `a`, `b` to Sass color (with all values normalized to `1`). |\n| `better.fallback('color', better.p3(#f00), #f00)` | Easy fallback constructor (meant for color, but may be used for anything). |\n| `better.mix(red, lime, 0.35)` | Mix `red` and `lime` 35%, i.e. more red. Uses Oklab for improved mixing. |\n| `better.lighten(#f00, 0.5)` | Lighten color by 50%, i.e. halfway to white (`1` is white; `0` is original color) |\n| `better.darken(#f00, 0.5)` | Darken color by 50%, i.e. halfway to black (`1` is black; `0` is original color) |\n| `better.lightness(#f00, 0.5)` | Get the human-perceived value of lightness from `0` (pure black) to `1` (pure white). |\n\n## Project summary\n\nThis project is meant to provide **the best possible method** for common color operations such as mixing, lightening/darkening, and conversion. This library is _not_ comprehensive, and doesn’t support any colorspaces that don’t serve a practical purpose\n(limiting colorspaces helps this library optimize for performance over completeness, not to mention ease-of-use). If you are well-versed in color science and need a comprehensive library, consider [Culori][culori] or [Color.js][colorjs] instead.\n\nTo learn more, see [Project Goals](./docs/faq.md#project-goals)\n\n[culori]: https://culorijs.org/\n[colorjs]: https://colorjs.io/\n[css-color]: https://www.w3.org/TR/css-color-5/#color-function\n[faq]: https://github.com/drwpow/better-color-tools/blob/main/faq.md\n[p3]: https://webkit.org/blog/10042/wide-gamut-color-in-css-with-display-p3/\n" | ||
} | ||
} |
@@ -36,15 +36,21 @@ # better-color-tools | ||
| Colorspace | Type | Example | | ||
| :---------- | :--------- | :------------------------------------------------- | | ||
| `.hex` | `string` | `'#ff0000'` | | ||
| `.hexVal` | `number` | `0xff0000` | | ||
| `.rgb` | `string` | `'rgb(255, 0, 0)'` | | ||
| `.rgbVal` | `number[]` | `[1, 0, 0, 1]` (R, G, B, alpha) | | ||
| `.p3` | `string` | `'color(display-p3 1 0 0)'` | | ||
| `.p3Val` | `number[]` | (alias for `rgbVal`) | | ||
| `.oklab` | `string` | `'color(oklab 0.62796 0.22486 0.12585)'` | | ||
| `.oklabVal` | `number[]` | `[0.62796, 0.22486, 0.12585, 1]` (L, a, b, alpha) | | ||
| `.oklch` | `string` | `'color(oklch 0.62796 0.25768 29.23389)'` | | ||
| `.oklchVal` | `number[]` | `[0.62796, 0.25768, 29.23389, 1]` (L, C, h, alpha) | | ||
| Colorspace | Type | Example | | ||
| :---------- | :--------- | :------------------------------------------ | | ||
| `.hex` | `string` | `'#ff0000'` | | ||
| `.hexVal` | `number` | `0xff0000` | | ||
| `.rgb` | `string` | `'rgb(255, 0, 0)'` | | ||
| `.rgbVal` | `number[]` | `[1, 0, 0, 1]` | | ||
| `.p3` | `string` | `'color(display-p3 1 0 0)'` | | ||
| `.p3Val` | `number[]` | (alias for `rgbVal`) | | ||
| `.oklab` | `string` | `'color(oklab 0.62796 0.22486 0.12585)'` | | ||
| `.oklabVal` | `number[]` | `[0.62796, 0.22486, 0.12585, 1]` | | ||
| `.oklch` | `string` | `'color(oklch 0.62796 0.25768 29.23389)'` | | ||
| `.oklchVal` | `number[]` | `[0.62796, 0.25768, 29.23389, 1]` | | ||
| `.xyz` | `string` | `'color(xyz-d65 0.62796 0.25768 29.23389)'` | | ||
| `.xyzVal` | `number[]` | `[0.62796, 0.25768, 29.23389, 1]` | | ||
| `.luv` | `string` | `'color(luv 0.53241 1.75015 0.2979)'` | | ||
| `.luvVal` | `number[]` | `[0.53241, 1.75015, 0.2979, 1]` | | ||
_Note: all colorspaces use the [CIE standard 2•, D65 white point observer](https://en.wikipedia.org/wiki/Illuminant_D65)._ | ||
### Sass | ||
@@ -51,0 +57,0 @@ |
@@ -17,2 +17,9 @@ // note: these types are all interchangeable, but are kept separate for readability | ||
const ε = 216 / 24389; | ||
const κ = 24389 / 27; | ||
const D65_WHITEPOINT = [95.47, 100, 108.33]; | ||
const D65_LUV_DENOMINATOR = D65_WHITEPOINT[0] + 15 * D65_WHITEPOINT[1] + 3 * D65_WHITEPOINT[2]; | ||
const D65_U_REF = (4 * D65_WHITEPOINT[0]) / D65_LUV_DENOMINATOR; | ||
const D65_V_REF = (9 * D65_WHITEPOINT[1]) / D65_LUV_DENOMINATOR; | ||
type MatrixRow = [number, number, number]; | ||
@@ -35,3 +42,3 @@ export type ColorMatrix = [MatrixRow, MatrixRow, MatrixRow]; | ||
// http://www.easyrgb.com/ | ||
// https://github.com/muak/ColorMinePortable/ | ||
export const LINEAR_RGB_TO_XYZ_D65: ColorMatrix = [ | ||
@@ -100,3 +107,3 @@ [0.4124, 0.3576, 0.1805], | ||
/** Lab -> LCh / Oklab -> Oklch)*/ | ||
/** Lab -> LCh / Oklab -> Oklch) */ | ||
export function labToLCH(lab: LAB): LCH { | ||
@@ -152,11 +159,6 @@ const [L, a, b, alpha] = lab; | ||
if (value <= 0.0031308) return clamp(value * 12.92, 0, 1); | ||
else return clamp(1.055 * value ** (1 / 2.4) - 0.055, 0, 1); | ||
else return clamp(1.055 * Math.pow(value, 1 / 2.4) - 0.055, 0, 1); | ||
}) as sRGB; | ||
} | ||
/** Linear sRGB -> XYZ (D65) */ | ||
export function linearRGBToXYZ(linearRGB: LinearRGB): XYZ_D65 { | ||
return multiplyColorMatrix(linearRGB, LINEAR_RGB_TO_XYZ_D65); | ||
} | ||
/** Linear sRGB -> LMS */ | ||
@@ -169,14 +171,16 @@ export function linearRGBToLMS(lrgb: LinearRGB): LMS { | ||
export function luvToXYZ(luv: LUV): XYZ_D65 { | ||
const [L, u, v, alpha] = luv; | ||
let [L, u, v, alpha] = luv; | ||
const xyz: XYZ_D65 = [0, 0, 0, alpha]; | ||
L *= 100; | ||
u *= 100; | ||
v *= 100; | ||
const y = L > ε * κ ? ((L + 16) / 116) ** 3 : L / κ; | ||
const a = ((52 * L) / (u + 13 * L * D65_U_REF) - 1) / 3 || 0; | ||
const b = -5 * y || 0; | ||
const c = -1 / 3; | ||
const d = y * ((39 * L) / (v + 13 * L * D65_V_REF) - 5) || 0; | ||
const x = (d - b) / (a - c) || 0; | ||
const z = x * a + b; | ||
const _u = u / (13 * L); | ||
const _v = v / (13 * L); | ||
xyz[1] = L <= 8 ? L * (3 / 29) ** 3 : ((L + 16) / 116) ** 3; // Y | ||
xyz[0] = xyz[1] * (9 / 4) * _u; // X | ||
xyz[2] = xyz[1] * (((12 - 3 * _u - 20 * _v) / 4) * _v); // Z | ||
return xyz; | ||
return [x, y, z, alpha]; | ||
} | ||
@@ -186,3 +190,3 @@ | ||
export function luvTosRGB(luv: LUV): sRGB { | ||
return linearRGBTosRGB(xyzToLinearRGB(luvToXYZ(luv))); | ||
return xyzTosRGB(luvToXYZ(luv)); | ||
} | ||
@@ -223,3 +227,3 @@ | ||
export function sRGBToLuv(rgb: sRGB): LUV { | ||
return xyzToLuv(linearRGBToXYZ(sRGBToLinearRGB(rgb))); | ||
return xyzToLuv(sRGBToXYZ(rgb)); | ||
} | ||
@@ -237,7 +241,12 @@ | ||
/** XYZ (D65) -> Linear sRGB */ | ||
export function xyzToLinearRGB(xyz: XYZ_D65): LinearRGB { | ||
return multiplyColorMatrix(xyz, XYZ_D65_TO_LINEAR_RGB); | ||
/** sRGB -> XYZ (D65) */ | ||
export function sRGBToXYZ(rgb: sRGB): XYZ_D65 { | ||
return multiplyColorMatrix(sRGBToLinearRGB(rgb), LINEAR_RGB_TO_XYZ_D65); | ||
} | ||
/** XYZ (D65) -> sRGB */ | ||
export function xyzTosRGB(xyz: XYZ_D65): LinearRGB { | ||
return linearRGBTosRGB(multiplyColorMatrix(xyz, XYZ_D65_TO_LINEAR_RGB)); | ||
} | ||
/** XYZ (D65) -> Luv */ | ||
@@ -247,13 +256,10 @@ export function xyzToLuv(xyz: XYZ_D65): LUV { | ||
const luv: LUV = [0, 0, 0, alpha]; | ||
const denominator = x + 15 * y + 3 * z; | ||
const _u = (4 * x) / denominator; | ||
const _v = (9 * y) / denominator; | ||
const _u = (4 * x) / denominator || 0; | ||
const _v = (9 * y) / denominator || 0; | ||
const L = x > ε ? 116 * Math.pow(y, 1 / 3) - 16 : κ * y; | ||
const u = 13 * L * (_u - D65_U_REF) || 0; // `|| 0` fixes -0 | ||
const v = 13 * L * (_v - D65_V_REF) || 0; | ||
luv[0] = x > 0.008856451679035631 ? 116 * y ** (1 / 3) - 16 : 903.2962962962961 * y; // L | ||
luv[1] = 13 * luv[0] * _u; // u | ||
luv[2] = 13 * luv[0] * _v; // v | ||
return luv; | ||
return [L / 100, u / 100, v / 100, alpha]; | ||
} |
@@ -1,4 +0,4 @@ | ||
import type { Color, LinearRGB, Oklab, Oklch, sRGB } from './colorspace.js'; | ||
import { Color, LinearRGB, LUV, Oklab, Oklch, sRGB, sRGBToXYZ, xyzTosRGB, XYZ_D65 } from './colorspace.js'; | ||
import { hslTosRGB, linearRGBTosRGB, luvTosRGB, oklabTosRGB, oklchTosRGB, sRGBToLinearRGB, sRGBToOklab, sRGBToOklch } from './colorspace.js'; | ||
import { hslTosRGB, linearRGBTosRGB, luvTosRGB, oklabTosRGB, oklchTosRGB, sRGBToLinearRGB, sRGBToLuv, sRGBToOklab, sRGBToOklch } from './colorspace.js'; | ||
import cssNames from './css-names.js'; | ||
@@ -23,5 +23,5 @@ import { clamp, colorFn, leftPad, rgbFn, round } from './utils.js'; | ||
/** `color(luv 0 0 0/1)` */ | ||
// luv: string; // TODO: fix bug | ||
luv: string; // TODO: fix bug | ||
/** [L, u, v, alpha] */ | ||
// luvVal: LUV; | ||
luvVal: LUV; | ||
/** `color(display-p3 0 0 0/1)` */ | ||
@@ -39,2 +39,6 @@ p3: string; | ||
oklchVal: Oklch; | ||
/** `color(xyz 0 0 0/1)` (2•, D65 whitepoint) */ | ||
xyz: string; | ||
/** [X, Y, Z, alpha] (2•, D65 whitespace) */ | ||
xyzVal: XYZ_D65; | ||
toString(): string; // JS helper | ||
@@ -77,3 +81,3 @@ } | ||
get hexVal(): number { | ||
if (color[3] < 1) console.warn(`hexVal converted a semi-transparent color (${color[3] * 100}%) to fully opaque`); | ||
if (color[3] < 1) console.warn(`hexVal converted a semi-transparent color (${color[3] * 100}%) to fully opaque`); // eslint-disable-line no-console | ||
const r = Math.round(color[0] * 255); | ||
@@ -84,8 +88,8 @@ const g = Math.round(color[1] * 255); | ||
}, | ||
// get luv(): string { | ||
// return colorFn('luv', sRGBToLuv(color)); | ||
// }, | ||
// get luvVal(): LUV { | ||
// return sRGBToLuv(color); | ||
// }, | ||
get luv(): string { | ||
return colorFn('luv', sRGBToLuv(color)); | ||
}, | ||
get luvVal(): LUV { | ||
return sRGBToLuv(color); | ||
}, | ||
get rgb(): string { | ||
@@ -118,2 +122,8 @@ return rgbFn(color); | ||
}, | ||
get xyz(): string { | ||
return colorFn('xyz-d65', sRGBToXYZ(color)); | ||
}, | ||
get xyzVal(): XYZ_D65 { | ||
return sRGBToXYZ(color); | ||
}, | ||
}; | ||
@@ -184,3 +194,2 @@ | ||
// named color | ||
// console.log({ val: strVal, name: (cssNames as any)[strVal] }); | ||
if (cssNames[strVal.toLowerCase()]) { | ||
@@ -241,3 +250,4 @@ return cssNames[strVal.toLowerCase()]; | ||
case 'luv': { | ||
return luvTosRGB(parseValueStr(valueStr, [1, 1, 1, 1])); | ||
const luv = parseValueStr(valueStr, [1, 1, 1, 1]); | ||
return luvTosRGB(luv); | ||
} | ||
@@ -250,2 +260,6 @@ case 'oklab': { | ||
} | ||
case 'xyz': | ||
case 'xyz-d65': { | ||
return xyzTosRGB(parseValueStr(valueStr, [1, 1, 1, 1])); | ||
} | ||
} | ||
@@ -252,0 +266,0 @@ } |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
217238
32
1770
88
15