转换方法
RGB => HSL
const rgb2hsl = (r, g, b) => {
r = r / 255
g = g / 255
b = b / 255
const max = Math.max(r, g, b)
const min = Math.min(r, g, b)
const d = max - min
const l = (max + min) / 2
const s = d === 0 ? 0 : l > 0.5 ? d / (2 - 2 * l) : d / (2 * l)
let h = 0
if (d !== 0) {
switch (max) {
case r:
h = (g - b) / d + (g < b ? 6 : 0)
break
case g:
h = (b - r) / d + 2
break
case b:
h = (r - g) / d + 4
break
default:
break
}
h = h / 6
}
return { h: h * 360, s: s * 100, l: l * 100 }
}
RGB => HSV
const rgb2hsv = (r, g, b) => {
r = r / 255
g = g / 255
b = b / 255
const max = Math.max(r, g, b)
const min = Math.min(r, g, b)
const d = max - min
const v = max
const s = max === 0 ? 0 : d / max
let h = 0
if (d !== 0) {
switch (max) {
case r:
h = (g - b) / d + (g < b ? 6 : 0)
break
case g:
h = (b - r) / d + 2
break
case b:
h = (r - g) / d + 4
break
default:
break
}
h = h / 6
}
return { h: h * 360, s, v }
}
HSV => HSL
const hsv2hsl = (h, s, v) => {
const t = (2 - s) * v
s = v === 0 || s === 0 ? 0 : (s * v) / (t > 1 ? 2 - t : t)
return { h, s: s * 100, l: (t / 2) * 100 }
}
公式的推导过程:
首先在 RGB => HSL 和 RGB => HSV 两个方法中唯二的两处差异,其中 max 和 min 是相同的
RGB => HSL (将 s 标记为 s1)
const l = (max + min) / 2
const s1 = d === 0 ? 0 : l > 0.5 ? d / (2 - 2 * l) : d / (2 * l)
RGB => HSV (将 s 标记为 s2)
const v = max
const s2 = max === 0 ? 0 : d / max
那么,在 HSV => HSL 推导过程中,
已知 HSV 中的 v === max,所以用 v 替换 max 带入公式
s2 = max === 0 ? 0 : (max - min) / max
==> s2 = v === 0 ? 0 : (v - min) / v
s2 = (v - min) / v
==> s2 * v = v - min
==> min = (1 - s2) * v
d = max - min
==> d = v - (1 - s2) * v
==> d = s2 * v
l = (v + min) / 2
==> 2 * l = v + (1 - s2) * v
==> 2 * l = (2 - s2) * v
s1 = d === 0 ? 0 : l > 0.5 ? d / (2 - 2 * l) : d / (2 * l)
==> s1 = s2 * v === 0 ? 0 : t > 1 ? (s2 * v) / (2 - t) : (s2 * v) / t
s1 = t > 1 ? (s2 * v) / (2 - t) : (s2 * v) / t
==> (s2 * v) / (t > 1 ? 2 - t : t)
l = t / 2
s1 = (s2 * v) / (t > 1 ? 2 - t : t)
s2 === 0
t === 0
==> l === 0
==> s1 === 0
t === 2 * v
==> l === v
==> s1 === 0
t = (2 - s2) * v
l = t / 2
s1 = (v === 0 || s === 0) ? 0 : (s2 * v) / (t > 1 ? 2 - t : t)
HSL => HSV
const hsl2hsv = (h, s, l) => {
s = s / 100
l = l / 100
let v = 0
if (s === 0) {
v = l
} else if (l > 0.5) {
v = l + s * (1 - l)
s = v === 0 ? 0 : (2 * s * (1 - l)) / v
} else {
v = l * (s + 1)
s = v === 0 ? 0 : (2 * s) / (s + 1)
}
return { h, s, v }
}
公式的推导过程:
首先在 RGB => HSL 和 RGB => HSV 两个方法中唯二的两处差异,其中 max 和 min 是相同的
RGB => HSL (将 s 标记为 s1)
const l = (max + min) / 2
const s1 = d === 0 ? 0 : l > 0.5 ? d / (2 - 2 * l) : d / (2 * l)
RGB => HSV (将 s 标记为 s2)
const v = max
const s2 = max === 0 ? 0 : d / max
那么,在 HSL => HSV 推导过程中
已知 HSL 中的 l === (max + min) / 2,即 max + min = 2 * l
v = max
==> v = l
s2 = max === 0 ? 0 : (max - min) / max
==> s2 = max === 0 ? 0 : 0 / max
==> s2 = 0
2 * l = max + min
s1 = (max - min) / (2 - 2 * l)
==> s1 * (2 - 2 * l) = max - min
(2 * l) + (s1 * 2 * (1 - l)) = (max + min) + (max - min)
==> l + s1 * (1 - l) = max
(2 * l) - (s1 * 2 * (1 - l)) = (max + min) - (max - min)
==> l - s1 * (1 - l) = min
v = l + s1 * (1 - l)
s2 = max === 0 ? 0 : (max - min) / max
==> s2 = v === 0 ? 0 : (l + s1 * (1 - l) - (l - s1 * (1 - l))) / v
==> s2 = v === 0 ? 0 : (2 * s1 * (1 - l)) / v
2 * l = max + min
s1 = (max - min) / (2 * l)
==> 2 * l * s1 = max - min
(2 * l) + (2 * l * s1) = (max + min) + (max - min)
==> l * (1 + s1) = max
(2 * l) - (2 * l * s1) = (max + min) - (max - min)
==> l * (1 - s1) = min
v = l * (1 + s1)
s2 = max === 0 ? 0 : d / max
==> s2 = v === 0 ? 0 : (l * (1 + s1) - l * (1 - s1)) / (l * (1 + s1))
==> s2 = v === 0 ? 0 : (2 * s1) / (1 + s1)
HSL => RGB
const hsl2rgb = (h, s, l) => {
h = h / 360
s = s / 100
l = l / 100
let r = l
let g = l
let b = l
if (s !== 0) {
const q = l < 0.5 ? l * (1 + s) : l + s - l * s
const p = 2 * l - q
const hue2rgb = (p, q, t) => {
if (t < 0) t += 1
if (t > 1) t -= 1
if (t < 1 / 6) return p + (q - p) * 6 * t
if (t < 1 / 2) return q
if (t < 2 / 3) return p + (q - p) * 6 * (2 / 3 - t)
return p
}
r = hue2rgb(p, q, h + 1 / 3)
g = hue2rgb(p, q, h)
b = hue2rgb(p, q, h - 1 / 3)
}
return { r: r * 255, g: g * 255, b: b * 255 }
}
HSV => RGB
const hsv2rgb = (h, s, v) => {
h = h / 360
h = h < 1 ? h * 6 : 0
const mod = Math.floor(h)
const f = h - mod
const p = v * (1 - s)
const q = v * (1 - f * s)
const t = v * (1 - (1 - f) * s)
const r = [v, q, p, p, t, v][mod]
const g = [t, v, v, q, p, p][mod]
const b = [p, p, t, v, v, q][mod]
return { r: r * 255, g: g * 255, b: b * 255 }
}
测试
let rgb = [255, 255, 255]
let hsl = rgb2hsl(...rgb)
let hsv = rgb2hsv(...rgb)
hsl2rgb(...Object.values(hsl))
hsv2rgb(...Object.values(hsv))
hsl2hsv(...Object.values(hsl))
hsv2hsl(...Object.values(hsv))
let rgb = [0, 0, 0]
let hsl = rgb2hsl(...rgb)
let hsv = rgb2hsv(...rgb)
hsl2rgb(...Object.values(hsl))
hsv2rgb(...Object.values(hsv))
hsl2hsv(...Object.values(hsl))
hsv2hsl(...Object.values(hsv))
let rgb = [255, 0, 255]
let hsl = rgb2hsl(...rgb)
let hsv = rgb2hsv(...rgb)
hsl2rgb(...Object.values(hsl))
hsv2rgb(...Object.values(hsv))
hsl2hsv(...Object.values(hsl))
hsv2hsl(...Object.values(hsv))
let rgb = [0, 0, 255]
let hsl = rgb2hsl(...rgb)
let hsv = rgb2hsv(...rgb)
hsl2rgb(...Object.values(hsl))
hsv2rgb(...Object.values(hsv))
hsl2hsv(...Object.values(hsl))
hsv2hsl(...Object.values(hsv))
let rgb = [72, 201, 176]
let hsl = rgb2hsl(...rgb)
let hsv = rgb2hsv(...rgb)
hsl2rgb(...Object.values(hsl))
hsv2rgb(...Object.values(hsv))
hsl2hsv(...Object.values(hsl))
hsv2hsl(...Object.values(hsv))
let rgb = [97, 106, 107]
let hsl = rgb2hsl(...rgb)
let hsv = rgb2hsv(...rgb)
hsl2rgb(...Object.values(hsl))
hsv2rgb(...Object.values(hsv))
hsl2hsv(...Object.values(hsl))
hsv2hsl(...Object.values(hsv))
let rgb = [3, 155, 229]
let hsl = rgb2hsl(...rgb)
let hsv = rgb2hsv(...rgb)
hsl2rgb(...Object.values(hsl))
hsv2rgb(...Object.values(hsv))
hsl2hsv(...Object.values(hsl))
hsv2hsl(...Object.values(hsv))
参考