-
-
Notifications
You must be signed in to change notification settings - Fork 85
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add HCT gamut mapping and HCT color distance (#420)
* Add HCT gamut mapping and HCT color distance - Add an HCT color distancing to keep from converting out of HCT which can be slower. Since HCT is based on CAM16, convert the C and h components to CAM16 UCS a and b. Perform euclidean distance on the resulting Lab lightness (tone) and CAM16 a and b. - Add support for HCT gamut mapping. Add two keywords to configure HCT gamut mapping. "hct" giving a normal gamut mapping assuming a JND of 2 and "hct-tonal" which will perform a tighter gamut mapping with a JND of close to zero and will force clamping of black and white based on tone value. This will give results that quite close to Material's tonal palettes. - toGamut has been extended to allow configuring the delta E method used, the JND, and enabling white and black SDR clamp. - Epsilon is now generically calculated to be relative to the JND. - The epsilon of min/max bisect threshold is still based on the JND epsilon, but now it is arbitrarily clamped to 1e-6 to prevent calculating a very small epsilon that could cause infinite loops. - Gamut tests have been extended to allow for converting to target space after gamut mapping (if needed). This is used to demonstrate tonal maps which require us (for best results) to stay in HCT. * Fix types, doc strings, formatting, and epsilon * Export delta E HCT in type definitions * Allow Ref type for blackWhiteClamp.channel * Because we stay in mappedColor if already in it, we need to resolve NaN * Fix linting in type file
- Loading branch information
1 parent
4cf563f
commit decf024
Showing
7 changed files
with
267 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import hct from "../spaces/hct.js"; | ||
import {viewingConditions} from "../spaces/hct.js"; | ||
|
||
const rad2deg = 180 / Math.PI; | ||
const deg2rad = Math.PI / 180; | ||
const ucsCoeff = [1.00, 0.007, 0.0228]; | ||
|
||
/** | ||
* Convert HCT chroma and hue (CAM16 JMh colorfulness and hue) using UCS logic for a and b. | ||
* @param {number[]} 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 {Color} color - Color to compare. | ||
* @param {Color} sample - Color to compare. | ||
* @return {number[]} | ||
*/ | ||
export default function (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); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import Color, { ColorObject } from "../color.js"; | ||
export default function ( | ||
color: Color | ColorObject, | ||
sample: Color | ColorObject | ||
): number; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters