Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 14x 14x 7x 7x 7x 7x 7x 14x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 7x 7x 7x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 7x 7x 7x 1x 1x 1x 1x 1x 7x 1x 1x 1x 1x 1x 42x |
/** @import { LabColor } from './color-types.d.js' */
const { sqrt, pow, cos, atan2, sin, abs, exp, PI, hypot } = Math
/**
* Returns diff between c1 and c2 using the CIEDE2000 algorithm
*
* Implemented as in "The CIEDE2000 Color-Difference Formula:
* Implementation Notes, Supplementary Test Data, and Mathematical Observations"
* by Gaurav Sharma, Wencheng Wu and Edul N. Dalal.
*
* @param {LabColor} c1 CIE L*a*b* color object, should have fields L,a,b
* @param {LabColor} c2 CIE L*a*b* color object, should have fields L,a,b
* @returns {number} Difference between c1 and c2
*/
export function ciede2000 (c1, c2) {
// Get L,a,b values for color 1
const L1 = c1.L
const a1 = c1.a
const b1 = c1.b
// Get L,a,b values for color 2
const L2 = c2.L
const a2 = c2.a
const b2 = c2.b
// Weight factors
const kL = 1
const kC = 1
const kH = 1
/**
* Step 1: Calculate C₁', C₂', h₁', h₂'
*/
const C1 = hypot(a1, b1) // C₁ (2)
const C2 = hypot(a2, b2) // C₂ (2)
const a_C1_C2 = (C1 + C2) / 2.0 // (3)
const G = 0.5 * (1 - sqrt(pow(a_C1_C2, 7.0) /
(pow(a_C1_C2, 7.0) + 25.0 ** 7.0))) // (4)
const a1p = (1.0 + G) * a1 // (5)
const a2p = (1.0 + G) * a2 // (5)
const C1p = hypot(a1p, b1) // C₁' (6)
const C2p = hypot(a2p, b2) // C₂' (6)
const h1p = hp_f(b1, a1p) // h₁' (7)
const h2p = hp_f(b2, a2p) // h₂' (7)
/**
* Step 2: Calculate 𝚫L', 𝚫C', 𝚫H'
*/
const dLp = L2 - L1 // 𝚫L' (8)
const dCp = C2p - C1p // 𝚫C' (9)
const dhp = dhp_f(C1, C2, h1p, h2p) // (10)
const dHp = 2 * sqrt(C1p * C2p) * sin(radians(dhp) / 2.0) // 𝚫H' (11)
/**
* Step 3: Calculate CIEDE2000 Color-Difference
*/
const a_L = (L1 + L2) / 2.0 // (12)
const a_Cp = (C1p + C2p) / 2.0 // (13)
const a_hp = a_hp_f(C1, C2, h1p, h2p) // (14)
const T = 1 - 0.17 * cos(radians(a_hp - 30)) + 0.24 * cos(radians(2 * a_hp)) +
0.32 * cos(radians(3 * a_hp + 6)) - 0.20 * cos(radians(4 * a_hp - 63)) // (15)
const d_ro = 30 * exp(-(pow((a_hp - 275) / 25, 2))) // (16)
const RC = sqrt((pow(a_Cp, 7.0)) / (pow(a_Cp, 7.0) + pow(25.0, 7.0)))// (17)
const SL = 1 + ((0.015 * pow(a_L - 50, 2)) /
sqrt(20 + pow(a_L - 50, 2.0)))// (18)
const SC = 1 + 0.045 * a_Cp// (19)
const SH = 1 + 0.015 * a_Cp * T// (20)
const RT = -2 * RC * sin(radians(2 * d_ro))// (21)
// (22)
return sqrt(pow(dLp / (SL * kL), 2) + pow(dCp / (SC * kC), 2) +
pow(dHp / (SH * kH), 2) + RT * (dCp / (SC * kC)) *
(dHp / (SH * kH)))
}
/**
* Calculates h' value, follows the next formula:
*
* ⎧ 0 b*=a'=0
* h' = ⎨
* ⎩ tan⁻¹(b*, a') otherwise
*
* @param {number} x - b* value
* @param {number} y - a' value
* @returns {number} h' value
*/
function hp_f (x, y) { // (7)
if (x === 0 && y === 0) {return 0}
else {
const tmp_hp = degrees(atan2(x, y))
if (tmp_hp >= 0) {return tmp_hp}
else {return tmp_hp + 360}
}
}
/**
* Calculates 𝚫h' value, follows the next formula:
*
* ⎧ 0 C₁'C₂'=0
* ⎪
* ⎪ h₂'-h₁' C₁'C₂'≠0; |h₂'-h₁'|≤180°
* 𝚫h' = ⎨
* ⎪ h₂'-h₁'-360 C₁'C₂'≠0; (h₂'-h₁')>180°
* ⎪
* ⎩ h₂'-h₁'+360 C₁'C₂'≠0; (h₂'-h₁')<-180°
*
* @param {number} C1 - C₁' value
* @param {number} C2 - C₂' value
* @param {number} h1p - h₁' value
* @param {number} h2p - h₂' value
* @returns {number} 𝚫h' value
*/
function dhp_f (C1, C2, h1p, h2p) { // (10)
if (C1 * C2 === 0) {return 0}
else if (abs(h2p - h1p) <= 180) {return h2p - h1p}
else if ((h2p - h1p) > 180) {return (h2p - h1p) - 360}
else if ((h2p - h1p) < -180) {return (h2p - h1p) + 360}
else {throw (new Error())}
}
/**
* Calculates h͞' value, follows the next formula:
*
* ⎧ h₁'+h₂' C₁'C₂'=0
* ⎪
* ⎪ h₁'+h₂' C₁'C₂'≠0; |h₁'-h₂'|≤180°
* ⎪ ───────
* ⎪ 2
* ⎪
* h͞' = ⎨ h₁'+h₂'+360 C₁'C₂'≠0; |h₁'-h₂'|>180°; (h₁'+h₂')<360°
* ⎪ ───────────
* ⎪ 2
* ⎪
* ⎪ h₁'+h₂'-360 C₁'C₂'≠0; |h₁'-h₂'|>180°; (h₁'+h₂')≥360°
* ⎪ ───────────
* ⎩ 2
*
* @param {number} C1 - C₁' value
* @param {number} C2 - C₂' value
* @param {number} h1p - h₁' value
* @param {number} h2p - h₂' value
* @returns {number} 𝚫h' value
*/
function a_hp_f (C1, C2, h1p, h2p) { // (14)
if (C1 * C2 === 0) {return h1p + h2p}
else if (abs(h1p - h2p) <= 180) {return (h1p + h2p) / 2.0}
else if ((abs(h1p - h2p) > 180) && ((h1p + h2p) < 360)) {return (h1p + h2p + 360) / 2.0}
else if ((abs(h1p - h2p) > 180) && ((h1p + h2p) >= 360)) {return (h1p + h2p - 360) / 2.0}
else {throw (new Error())}
}
/**
* Converts radians to degrees
* @param {number} radians - number in radians
*/
function degrees (radians) { return radians * (180 / PI) }
/**
* Converts degrees to radians
* @param {number} degrees - number in degrees
*/
function radians (degrees) { return degrees * (PI / 180) }
|