|
@@ -1,4 +1,6 @@
|
|
import { clamp, euclideanModulo, lerp } from './MathUtils.js';
|
|
import { clamp, euclideanModulo, lerp } from './MathUtils.js';
|
|
|
|
+import { ColorManagement, SRGBToLinear, LinearToSRGB } from './ColorManagement.js';
|
|
|
|
+import { SRGBColorSpace, LinearSRGBColorSpace } from '../constants.js';
|
|
|
|
|
|
const _colorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF,
|
|
const _colorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF,
|
|
'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2,
|
|
'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2,
|
|
@@ -25,6 +27,7 @@ const _colorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua'
|
|
'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0,
|
|
'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0,
|
|
'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 };
|
|
'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 };
|
|
|
|
|
|
|
|
+const _rgb = { r: 0, g: 0, b: 0 };
|
|
const _hslA = { h: 0, s: 0, l: 0 };
|
|
const _hslA = { h: 0, s: 0, l: 0 };
|
|
const _hslB = { h: 0, s: 0, l: 0 };
|
|
const _hslB = { h: 0, s: 0, l: 0 };
|
|
|
|
|
|
@@ -39,15 +42,13 @@ function hue2rgb( p, q, t ) {
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
-function SRGBToLinear( c ) {
|
|
|
|
|
|
+function toComponents( source, target ) {
|
|
|
|
|
|
- return ( c < 0.04045 ) ? c * 0.0773993808 : Math.pow( c * 0.9478672986 + 0.0521327014, 2.4 );
|
|
|
|
|
|
+ target.r = source.r;
|
|
|
|
+ target.g = source.g;
|
|
|
|
+ target.b = source.b;
|
|
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-function LinearToSRGB( c ) {
|
|
|
|
-
|
|
|
|
- return ( c < 0.0031308 ) ? c * 12.92 : 1.055 * ( Math.pow( c, 0.41666 ) ) - 0.055;
|
|
|
|
|
|
+ return target;
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
@@ -96,7 +97,7 @@ class Color {
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- setHex( hex ) {
|
|
|
|
|
|
+ setHex( hex, colorSpace = SRGBColorSpace ) {
|
|
|
|
|
|
hex = Math.floor( hex );
|
|
hex = Math.floor( hex );
|
|
|
|
|
|
@@ -104,21 +105,25 @@ class Color {
|
|
this.g = ( hex >> 8 & 255 ) / 255;
|
|
this.g = ( hex >> 8 & 255 ) / 255;
|
|
this.b = ( hex & 255 ) / 255;
|
|
this.b = ( hex & 255 ) / 255;
|
|
|
|
|
|
|
|
+ ColorManagement.toWorkingColorSpace( this, colorSpace );
|
|
|
|
+
|
|
return this;
|
|
return this;
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- setRGB( r, g, b ) {
|
|
|
|
|
|
+ setRGB( r, g, b, colorSpace = LinearSRGBColorSpace ) {
|
|
|
|
|
|
this.r = r;
|
|
this.r = r;
|
|
this.g = g;
|
|
this.g = g;
|
|
this.b = b;
|
|
this.b = b;
|
|
|
|
|
|
|
|
+ ColorManagement.toWorkingColorSpace( this, colorSpace );
|
|
|
|
+
|
|
return this;
|
|
return this;
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- setHSL( h, s, l ) {
|
|
|
|
|
|
+ setHSL( h, s, l, colorSpace = LinearSRGBColorSpace ) {
|
|
|
|
|
|
// h,s,l ranges are in 0.0 - 1.0
|
|
// h,s,l ranges are in 0.0 - 1.0
|
|
h = euclideanModulo( h, 1 );
|
|
h = euclideanModulo( h, 1 );
|
|
@@ -140,11 +145,13 @@ class Color {
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ ColorManagement.toWorkingColorSpace( this, colorSpace );
|
|
|
|
+
|
|
return this;
|
|
return this;
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- setStyle( style ) {
|
|
|
|
|
|
+ setStyle( style, colorSpace = SRGBColorSpace ) {
|
|
|
|
|
|
function handleAlpha( string ) {
|
|
function handleAlpha( string ) {
|
|
|
|
|
|
@@ -181,6 +188,8 @@ class Color {
|
|
this.g = Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255;
|
|
this.g = Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255;
|
|
this.b = Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255;
|
|
this.b = Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255;
|
|
|
|
|
|
|
|
+ ColorManagement.toWorkingColorSpace( this, colorSpace );
|
|
|
|
+
|
|
handleAlpha( color[ 4 ] );
|
|
handleAlpha( color[ 4 ] );
|
|
|
|
|
|
return this;
|
|
return this;
|
|
@@ -194,6 +203,8 @@ class Color {
|
|
this.g = Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100;
|
|
this.g = Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100;
|
|
this.b = Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100;
|
|
this.b = Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100;
|
|
|
|
|
|
|
|
+ ColorManagement.toWorkingColorSpace( this, colorSpace );
|
|
|
|
+
|
|
handleAlpha( color[ 4 ] );
|
|
handleAlpha( color[ 4 ] );
|
|
|
|
|
|
return this;
|
|
return this;
|
|
@@ -214,7 +225,7 @@ class Color {
|
|
|
|
|
|
handleAlpha( color[ 4 ] );
|
|
handleAlpha( color[ 4 ] );
|
|
|
|
|
|
- return this.setHSL( h, s, l );
|
|
|
|
|
|
+ return this.setHSL( h, s, l, colorSpace );
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
@@ -236,6 +247,8 @@ class Color {
|
|
this.g = parseInt( hex.charAt( 1 ) + hex.charAt( 1 ), 16 ) / 255;
|
|
this.g = parseInt( hex.charAt( 1 ) + hex.charAt( 1 ), 16 ) / 255;
|
|
this.b = parseInt( hex.charAt( 2 ) + hex.charAt( 2 ), 16 ) / 255;
|
|
this.b = parseInt( hex.charAt( 2 ) + hex.charAt( 2 ), 16 ) / 255;
|
|
|
|
|
|
|
|
+ ColorManagement.toWorkingColorSpace( this, colorSpace );
|
|
|
|
+
|
|
return this;
|
|
return this;
|
|
|
|
|
|
} else if ( size === 6 ) {
|
|
} else if ( size === 6 ) {
|
|
@@ -245,6 +258,8 @@ class Color {
|
|
this.g = parseInt( hex.charAt( 2 ) + hex.charAt( 3 ), 16 ) / 255;
|
|
this.g = parseInt( hex.charAt( 2 ) + hex.charAt( 3 ), 16 ) / 255;
|
|
this.b = parseInt( hex.charAt( 4 ) + hex.charAt( 5 ), 16 ) / 255;
|
|
this.b = parseInt( hex.charAt( 4 ) + hex.charAt( 5 ), 16 ) / 255;
|
|
|
|
|
|
|
|
+ ColorManagement.toWorkingColorSpace( this, colorSpace );
|
|
|
|
+
|
|
return this;
|
|
return this;
|
|
|
|
|
|
}
|
|
}
|
|
@@ -253,7 +268,7 @@ class Color {
|
|
|
|
|
|
if ( style && style.length > 0 ) {
|
|
if ( style && style.length > 0 ) {
|
|
|
|
|
|
- return this.setColorName( style );
|
|
|
|
|
|
+ return this.setColorName( style, colorSpace );
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
@@ -261,7 +276,7 @@ class Color {
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- setColorName( style ) {
|
|
|
|
|
|
+ setColorName( style, colorSpace = SRGBColorSpace ) {
|
|
|
|
|
|
// color keywords
|
|
// color keywords
|
|
const hex = _colorKeywords[ style.toLowerCase() ];
|
|
const hex = _colorKeywords[ style.toLowerCase() ];
|
|
@@ -269,7 +284,7 @@ class Color {
|
|
if ( hex !== undefined ) {
|
|
if ( hex !== undefined ) {
|
|
|
|
|
|
// red
|
|
// red
|
|
- this.setHex( hex );
|
|
|
|
|
|
+ this.setHex( hex, colorSpace );
|
|
|
|
|
|
} else {
|
|
} else {
|
|
|
|
|
|
@@ -334,23 +349,27 @@ class Color {
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- getHex() {
|
|
|
|
|
|
+ getHex( colorSpace = SRGBColorSpace ) {
|
|
|
|
+
|
|
|
|
+ ColorManagement.fromWorkingColorSpace( toComponents( this, _rgb ), colorSpace );
|
|
|
|
|
|
- return clamp( this.r * 255, 0, 255 ) << 16 ^ clamp( this.g * 255, 0, 255 ) << 8 ^ clamp( this.b * 255, 0, 255 ) << 0;
|
|
|
|
|
|
+ return clamp( _rgb.r * 255, 0, 255 ) << 16 ^ clamp( _rgb.g * 255, 0, 255 ) << 8 ^ clamp( _rgb.b * 255, 0, 255 ) << 0;
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- getHexString() {
|
|
|
|
|
|
+ getHexString( colorSpace = SRGBColorSpace ) {
|
|
|
|
|
|
- return ( '000000' + this.getHex().toString( 16 ) ).slice( - 6 );
|
|
|
|
|
|
+ return ( '000000' + this.getHex( colorSpace ).toString( 16 ) ).slice( - 6 );
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- getHSL( target ) {
|
|
|
|
|
|
+ getHSL( target, colorSpace = LinearSRGBColorSpace ) {
|
|
|
|
|
|
// h,s,l ranges are in 0.0 - 1.0
|
|
// h,s,l ranges are in 0.0 - 1.0
|
|
|
|
|
|
- const r = this.r, g = this.g, b = this.b;
|
|
|
|
|
|
+ ColorManagement.fromWorkingColorSpace( toComponents( this, _rgb ), colorSpace );
|
|
|
|
+
|
|
|
|
+ const r = _rgb.r, g = _rgb.g, b = _rgb.b;
|
|
|
|
|
|
const max = Math.max( r, g, b );
|
|
const max = Math.max( r, g, b );
|
|
const min = Math.min( r, g, b );
|
|
const min = Math.min( r, g, b );
|
|
@@ -389,9 +408,30 @@ class Color {
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- getStyle() {
|
|
|
|
|
|
+ getRGB( target, colorSpace = LinearSRGBColorSpace ) {
|
|
|
|
+
|
|
|
|
+ ColorManagement.fromWorkingColorSpace( toComponents( this, _rgb ), colorSpace );
|
|
|
|
+
|
|
|
|
+ target.r = _rgb.r;
|
|
|
|
+ target.g = _rgb.g;
|
|
|
|
+ target.b = _rgb.b;
|
|
|
|
+
|
|
|
|
+ return target;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ getStyle( colorSpace = SRGBColorSpace ) {
|
|
|
|
+
|
|
|
|
+ ColorManagement.fromWorkingColorSpace( toComponents( this, _rgb ), colorSpace );
|
|
|
|
+
|
|
|
|
+ if ( colorSpace !== SRGBColorSpace ) {
|
|
|
|
+
|
|
|
|
+ // Requires CSS Color Module Level 4 (https://www.w3.org/TR/css-color-4/).
|
|
|
|
+ return `color(${ colorSpace } ${ _rgb.r } ${ _rgb.g } ${ _rgb.b })`;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
|
|
- return 'rgb(' + ( ( this.r * 255 ) | 0 ) + ',' + ( ( this.g * 255 ) | 0 ) + ',' + ( ( this.b * 255 ) | 0 ) + ')';
|
|
|
|
|
|
+ return `rgb(${( _rgb.r * 255 ) | 0},${( _rgb.g * 255 ) | 0},${( _rgb.b * 255 ) | 0})`;
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|