一、十六进制转RGB
function hexToRgba(hex) {// 移除 # 字符hex = hex.replace('#', '');// 处理简写形式如 #fffif (hex.length === 3) {hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];}// 转换为十进制const r = parseInt(hex.substring(0, 2), 16); // 截图前两位,然后16进制转为10进制const g = parseInt(hex.substring(2, 4), 16);const b = parseInt(hex.substring(4, 6), 16);return `rgb(${r}, ${g}, ${b})`;}
- 使用十六进制表示颜色时,每两位代表一个颜色通道(#RRGGBB:RR=红,GG=绿,BB=蓝),范围00-FF(十进制0-255)。
二、RGB转十六进制
function rgbToHex(rgbStr) {// 提取 RGB 值const match = rgbStr.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)$/i);if (!match) {throw new Error('Invalid RGB/RGBA string format');}// 解析颜色分量const r = parseInt(match[1]);const g = parseInt(match[2]);const b = parseInt(match[3]);// 转换为十六进制const toHex = (num) => {const hex = Math.min(255, Math.max(0, num)).toString(16);return hex.length === 1 ? '0' + hex : hex;};return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
}
- 使用正则表达式匹配rgb/rgba
/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)$/i // (?:,\s*([\d.]+))?:可选捕获透明度部分
- 数值范围处理和十六进制转换
const toHex = (num) => {// 1. 确保颜色值在 0-255 范围内// 2. 处理可能的非法输入值// 3. 转为十六进制const hex = Math.min(255, Math.max(0, num)).toString(16);return hex.length === 1 ? '0' + hex : hex; };
三、十六进制转HSL
(一)、什么是HSL
HSL(Hue, Saturation, Lightness)是一种基于人类感知的颜色表示方法,广泛应用于计算机图形学、网页设计和图像处理等领域。它比传统的 RGB(红绿蓝)模型更直观,便于调整颜色的色调、鲜艳度和明暗。
(二)、HSL中H、S、L分别代表什么
H:色相(Hue, H)
- 定义:颜色的基本类型(如红、绿、蓝)。
- 范围:0°–360°(环形色轮)。
0° = 红色
120° = 绿色
240° = 蓝色
360° = 回到红色
色相和色度的区别
特性 | 色相(Hue) | 色度(Chroma) |
---|---|---|
定义 | 颜色的种类(红、绿、蓝等) | 颜色的纯度(鲜艳程度) |
几何表示 | 色轮上的角度(0°–360°) | 颜色点到灰度轴的距离 |
物理基础 | 光的波长 | 颜色成分的纯度(与灰度的偏离) |
调整效果 | 改变颜色类别(如红→蓝) | 改变颜色的鲜艳度(如鲜红→灰红) |
感知独立性 | 与明度、饱和度无关 | 与明度相关(明度影响最大色度) |
S:饱和度(Saturation, S)
- 定义:颜色的鲜艳程度(从灰度到纯色)。
- 范围:0%–100%
0% = 灰色(完全去色)
100% = 最鲜艳的颜色
L:明度(Lightness, L)
- 定义:颜色的明暗程度(从黑到白)。
- 范围:0%–100%
0% = 纯黑
50% = 标准颜色
100% = 纯白
(三)、HSL的圆柱模型
HSL还有双六棱锥模型,这里主要说圆柱模型
HSL(色相、饱和度、明度)的圆柱模型是一种直观的几何表示方式,将颜色的三个属性映射到三维空间中。
基本结构
- 色相(Hue, H)
- 几何位置:围绕圆柱的圆周方向(0°–360°)。
- 物理意义:颜色在色轮上的角度,决定颜色种类(如红、绿、蓝)。
- 饱和度(Saturation, S)
- 几何位置:从圆柱中心到边缘的径向距离(0%–100%)。
- 物理意义:颜色的鲜艳程度,中心为灰色,边缘为纯色。
- 明度(Lightness, L)
- 几何位置:沿圆柱的垂直轴高度(0%–100%)。
- 物理意义:颜色的明暗程度,底部为纯黑,顶部为纯白,中间为纯色。
关键几何特征
- 灰度轴(中心轴)
- 位置:圆柱的中心垂直线(S=0%)。
- 颜色特性:
- 所有点均为灰色,色相(H)无意义。
- 明度(L)决定灰度深浅:
- L=0% → 纯黑
- L=100% → 纯白
- L=50% → 中性灰
- 中间平面(L=50%)
- 位置:圆柱的中间水平截面(高度为 50%)。
- 颜色特性:
- 所有颜色处于最鲜艳状态(饱和度 S=100%)。
- 色相(H)在此平面上形成完整的 色相环(红→黄→绿→青→蓝→品红→红)。
- 顶部与底部
- 顶部(L=100%):
- 所有颜色均为纯白(无论色相和饱和度如何)。
- 底部(L=0%):
- 所有颜色均为纯黑(无论色相和饱和度如何)。
- 所有颜色均为纯黑(无论色相和饱和度如何)。
- 顶部(L=100%):
(四)、什么是RGB
RGB(Red, Green, Blue)是一种基于光学的颜色表示方法,通过红、绿、蓝三原色的不同比例混合来定义颜色。它是数字设备(如显示器、摄像头)最基础的颜色模型。
(五)、RGB中R、G、B分别代表什么
R:(Red,红色)
- 定义:红色光的强度,是光的三原色之一。
- 作用:红色分量主导颜色中的红色成分。
- 示例:纯红色的 RGB 值为 (255, 0, 0)。
G(Green,绿色)
- 定义:绿色光的强度,是光的三原色之一。
- 作用:绿色分量主导颜色中的绿色成分。
- 示例:纯绿色的 RGB 值为 (0, 255, 0)。
B(Blue,蓝色)
- 定义:蓝色光的强度,是光的三原色之一。
- 作用:蓝色分量主导颜色中的蓝色成分。
- 示例:纯蓝色的 RGB 值为 (0, 0, 255)。
(六)RGB的立方体模型
RGB 立方体模型是描述 RGB 颜色空间最直观的几何表示方式。它通过三维坐标系将红(R)、绿(G)、蓝(B)三个颜色分量的组合关系可视化,帮助理解颜色的混合规律和分布特性。
基本结构
RGB 立方体是一个三维直角坐标系:
-
三个坐标轴:
- R 轴(红色):从左(0)到右(255 或 1.0)
- G 轴(绿色):从前(0)到后(255 或 1.0)
- B 轴(蓝色):从下(0)到上(255 或 1.0)
-
顶点:立方体的 8 个顶点对应极端颜色值,例如:
- (0,0,0) → 纯黑色
- (255,255,255) → 纯白色
- (255,0,0) → 纯红色
- (0,255,0) → 纯绿色
- (0,0,255) → 纯蓝色
关键几何特征
-
灰度对角线
- 定义:从黑色 (0,0,0) 到白色 (255,255,255) 的对角线。
- 颜色特性:线上所有点满足 R=G=B,即 灰度色。
- 例如:(128,128,128) → 中灰色。
-
纯色顶点
-
6 个非黑白顶点:对应红、绿、蓝及其两两混合的纯色:
顶点坐标 颜色名称 (255,0,0) 纯红 (0,255,0) 纯绿 (0,0,255) 纯蓝 (255,255,0) 黄(红+绿) (255,0,255) 品红(红+蓝) (0,255,255) 青(绿+蓝)
-
-
颜色平面
- 单通道为 0 的平面:
- R=0 平面 → 蓝绿混合色(如青、蓝、绿)。
- G=0 平面 → 红蓝混合色(如品红、红、蓝)。
- B=0 平面 → 红绿混合色(如黄、红、绿)。
归一化如下图
- 单通道为 0 的平面:
(七)、十六进制转HSL
function hexToHsl(hex) {// 1. 去除#号并解析R,G,Blet r = parseInt(hex.slice(1, 3), 16) / 255;let g = parseInt(hex.slice(3, 5), 16) / 255;let b = parseInt(hex.slice(5, 7), 16) / 255;// 2. 计算最大值、最小值和色度(Chroma)let max = Math.max(r, g, b);let min = Math.min(r, g, b);let chroma = max - min;// 3. 计算明度(Lightness)let l = (max + min) / 2;// 4. 计算色相(Hue)和饱和度(Saturation)let h = 0, s = 0;if (chroma !== 0) {// 饱和度计算s = chroma / (1 - Math.abs(2 * l - 1));// 色相计算switch (max) {case r: h = ((g - b) / chroma) % 6; break;case g: h = (b - r) / chroma + 2; break;case b: h = (r - g) / chroma + 4; break;}h = h * 60;if (h < 0) h += 360; // 确保色相在0-360度之间}// 5. 返回HSL对象(色相四舍五入,饱和度和明度转为百分比)return {h: Math.round(h),s: Math.round(s * 100),l: Math.round(l * 100)};
}
使用max - min计算色度的几何意义
let max = Math.max(r, g, b);let min = Math.min(r, g, b);let chroma = max - min;
色度表示颜色点 P(R,G,B) 到灰度轴的垂直距离,即颜色偏离灰色的程度。:
- 当 C=0:颜色位于灰度轴上(完全无色彩)。
- 当 C=1:颜色为纯色(如纯红、纯绿、纯蓝)。
总结:当某个分量(如R)远大于其他分量时,max - min 的值越大,颜色越接近纯色(如纯红)。
数学推导
颜色点到灰度轴的距离(三维空间中的垂直距离)为:
而 C=max−min 是该距离的简化近似,避免了复杂的平方根运算, 但是忽略了部分分量差异。会导致色度越大,颜色越偏离灰色。
根号3的来源,使用到了空间向量相关知识。公式如下
使用(max - min)/2计算色度的几何意义
let l = (max + min) / 2;
明度表示颜色点在灰度轴上的投影位置。具体来说,颜色点 P(R,G,B)沿垂直于灰度轴的方向投影到灰度轴上,得到的投影点坐标为 (L,L,L)其中 L 是明度值。
- 示例:
- 纯红色 (1,0,0):
L=(1+0)/2=0.5,投影点为 (0.5,0.5,0.5),即中等灰色。 - 浅蓝色 (0.2,0.8,0.8):
L= (0.8+0.2)/2 =0.5,投影点仍为 (0.5,0.5,0.5)。
- 纯红色 (1,0,0):
数学推导
简化公式为
和色度一样,使用(max+min)/2 计算明度只需比较和一次加法,适合实时计算(如早期图形处理),同时还可以兼容HSL中饱和度的计算。
色度和明度对比
属性 | 几何意义 | 物理意义 | 计算依赖 |
---|---|---|---|
色度 | 颜色到灰度轴的垂直距离 | 颜色的纯度(偏离灰色的程度) | max 和 min 的差值 |
明度 | 颜色在灰度轴上的投影位置 | 颜色的整体亮度(等效灰色亮度) | max 和 min 的平均值 |
使用chroma / (1 - Math.abs(2 * l - 1))计算饱和度的几何意义
s = chroma / (1 - Math.abs(2 * l - 1));
这相当于:
- 在RGB立方体中,从当前颜色点向灰度轴作垂线
- 计算该点到灰度轴的距离(实际色度)
- 计算该明度平面上可能的最大色度
- 求两者的比值
可视化理解:
- 想象RGB立方体:
- 在L=0.5的中间平面,最大色度大(分母大),容易得到高饱和度
- 在L接近0或1的平面,最大色度小(分母小),饱和度被压缩
- 这种设计确保了:
- 纯色总是在L=0.5时S=100%
- 接近黑白时饱和度自动降低
计算色相的几何意义
switch (max) {case r: h = ((g - b) / chroma) % 6; break;case g: h = (b - r) / chroma + 2; break;case b: h = (r - g) / chroma + 4; break;}
为什么计算色相时需要分三段进行判断?
色相表示颜色在色轮上的位置(0°~360°),不同主色对应不同区间:
- 红色(R):0°(或360°)
- 绿色(G):120°
- 蓝色(B):240°
色相的计算需要根据最大值通道确定基础角度,再通过其他通道的相对差异调整偏移量。
当最大值是R时
case r: h = ((g - b) / chroma) % 6; break; // 这里 % 6 是为了防止差值出超过0-6之间的数值。如果差值超过0-6的范围那么%6可以回到范围
- 基础角度:0°(红色)
- 偏移方向:
- 若G > B → 向黄色(60°方向)偏移。
- 若B > G → 向品红色(300°方向)偏移。
- 计算公式:
- 几何意义:计算G和B的相对比例,归一化到[-1,1],再映射到0-6的临时值。
当最大值是G时
case g: h = (b - r) / chroma + 2; break;
- 基础角度:120°(绿色)
- 偏移方向:
- 若B > R → 向青色(180°方向)偏移。
- 若R > B → 向黄色(60°方向)偏移。
- 计算公式:
- 几何意义:+2 将结果偏移到绿色区域(120°)。
当最大值是B时
- 基础角度:240°(蓝色)
- 偏移方向:
- 若R > G → 向品红色(300°方向)偏移。
- 若G > R → 向青色(180°方向)偏移。
- 计算公式:
- 几何意义:+4 将结果偏移到蓝色区域(240°)
为什么计算色相时当最大值为r时公式里面是g-b为不是b-g?
色轮以 逆时针方向 定义颜色过渡:
红色(0°) → 黄色(60°) → 绿色(120°) → 青色(180°) → 蓝色(240°) → 品红(300°) → 红色(360°)。
当 R为最大值 时:
若 G > B,颜色偏向 黄色(60°方向),此时 (G - B) 为正,色相应 增加。
若 B > G,颜色偏向 品红色(300°方向),此时 (G - B) 为负,色相应 减少。
使用 (G - B) 而非 (B - G) 能直接反映这一方向性。(同样道理适用于最大值为g或b)
四、HSL转十六进制
function hslToHex(h, s, l) {// 规范化输入值h = h % 360;s = Math.max(0, Math.min(100, s)) / 100;l = Math.max(0, Math.min(100, l)) / 100;// 处理灰度色if (s === 0) {const gray = Math.round(l * 255);return `#${gray.toString(16).padStart(2, '0').repeat(3)}`;}// 计算色度、中间值和明度偏移const c = (1 - Math.abs(2 * l - 1)) * s;const x = c * (1 - Math.abs((h / 60) % 2 - 1));const m = l - c / 2;// 根据色相确定RGB初始值let r, g, b;if (h >= 0 && h < 60) {[r, g, b] = [c, x, 0];} else if (h < 120) {[r, g, b] = [x, c, 0];} else if (h < 180) {[r, g, b] = [0, c, x];} else if (h < 240) {[r, g, b] = [0, x, c];} else if (h < 300) {[r, g, b] = [x, 0, c];} else {[r, g, b] = [c, 0, x];}// 转换为十六进制const toHex = (value) => {const hex = Math.round((value + m) * 255).toString(16);return hex.padStart(2, '0');};return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
}
获取色度
const c = (1 - Math.abs(2 * l - 1)) * s;
是上面十六进制转为HSL中饱和度s=chroma / (1 - Math.abs(2 * l - 1)); 再乘以(1 - Math.abs(2 * l - 1))得到色度
计算中间颜色分量的值
const x = c * (1 - Math.abs((h / 60) % 2 - 1));
分步理解公式
- 色相分段:h / 60
- 将色相 H 按每 60° 分段,对应色轮上的 6 个主色区间(红、黄、绿、青、蓝、品红)。
- 模2操作:(h / 60) % 2
- 将分段后的色相值映射到 0~2 的范围内,用于在每段内生成对称的插值系数。
- 归一化到 -1~1:(h / 60) % 2 - 1
- 通过减去 1,将范围调整为 -1~1,便于后续的绝对值处理。
- 生成插值系数:1 - Math.abs(…)
- 取绝对值后,值域为 0~1,再用 1 减去它,得到 0→1→0 的三角形波形,用于颜色分量的平滑过渡。
- 乘以色度 C:c * …
- 最终结果表示中间颜色分量的强度,范围在 0~C 之间。
为什么乘以色度?
- 色度 C 表示颜色的纯度,插值系数与 C 相乘,确保颜色强度与饱和度一致。
- 高饱和度( 最大,颜色鲜艳)。
- 低饱和度(颜色为灰色)。
中间颜色分量的几何意义:
色相分段与颜色过渡
- 每 60° 对应一个颜色区间:
- 0°~60°:红色 → 黄色
- 60°~120°:黄色 → 绿色
- 120°~180°:绿色 → 青色
- 180°~240°:青色 → 蓝色
- 240°~300°:蓝色 → 品红
- 300°~360°:品红 → 红色
- 中间分量的作用:
在每个区间内,一个颜色分量保持最大值(由主色决定),另一个分量从 0 增长到最大值(或从最大值减少到 0),第三个分量保持为 0。- 例如:在 0°~60°(红→黄)区间:
- 红色分量 R=C(最大)
- 绿色分量 G=C×插值系数(从 0 到 C)
- 蓝色分量 B=0。
- 例如:在 0°~60°(红→黄)区间:
插值系数的波形
- 波形形状:
插值系数通过 1 - Math.abs((h / 60) % 2 - 1) 生成 三角形波形,在每 60° 区间内从 0 线性增长到 1,再线性减少到 0。- 示例:当 H=30°(0°~60°区间):
插值系数=1−∣(30/60)%2−1∣=1−∣0.5−1∣=0.5
此时绿色分量 G=C×0.5,颜色为橙色。
- 示例:当 H=30°(0°~60°区间):
计算明度偏移量
const m = l - c / 2;
计算明度偏移量的几何意义
平移中间分量:将中间分量(如 r′,g′,b ′)从相对范围 0∼C 平移到实际范围 L− C/2∼L+ C/2,保颜色在灰度轴上的投影亮度为 L。
计算明度偏移量的数据推导
HSL明度的定义:
- 在HSL模型中,明度 L 是RGB分量的最大值(max)和最小值(min)的算术平均值
色度 C 的定义:
- 色度(Chroma) 表示颜色的纯度,即RGB分量的最大值与最小值之差:
联立方程求解
- 通过联立上述两个方程,可以推导出 min 和 max:
- max:颜色分量的最大值(例如纯红色时 R=1)
- min:颜色分量的最小值(例如纯红色时 G=B=0)
明度偏移量 m 的引入
在HSL转RGB时,中间分量(如 r ′,g ′,b ′)是基于色相和饱和度计算出的相对值(范围0~C)。为了将这些中间分量映射到实际RGB值(范围0~1),需要加上一个偏移量 m,使得:
将 m=L− C/2代入,可保证:
从而满足HSL明度的定义。
根据色相区间确定 RGB 初始值
let r, g, b;if (h >= 0 && h < 60) {[r, g, b] = [c, x, 0];} else if (h < 120) {[r, g, b] = [x, c, 0];} else if (h < 180) {[r, g, b] = [0, c, x];} else if (h < 240) {[r, g, b] = [0, x, c];} else if (h < 300) {[r, g, b] = [x, 0, c];} else {[r, g, b] = [c, 0, x];}
色相区间 | 临时 RGB 值 |
---|---|
0°-60° | (C, X, 0) |
60°-120° | (X, C, 0) |
120°-180° | (0, C, X) |
180°-240° | (0, X, C) |
240°-300° | (X, 0, C) |
300°-360° | (C, 0, X) |
调整 RGB 值并转换为十六进制
const toHex = (value) => {const hex = Math.round((value + m) * 255).toString(16);return hex.padStart(2, '0');};
- 将 RGB 值加上明度偏移量 m,并限制在 0-1 范围内。
- 转换为 0-255 的整数,再转为两位十六进制。
五、十六进制转HSV
虽然HSV和HSL看着名字相似,但它们的定义和计算逻辑有本质区别。尽管在十六进制→HSL 和 十六进制→HSV(HSV → 十六进制 和 HSL → 十六进制) 的转换过程中,计算中间值(如色度 c 和辅助变量 x)或者色度等公式看起来相似,但它们的物理含义不同,最终转换结果也不同
(一)、什么是HSV
HSV(Hue, Saturation, Value)是一种基于人类颜色感知的模型,用于直观描述颜色的 色调、鲜艳度 和 亮度。它在图像处理、设计工具和数据可视化中广泛应用。
(二)、HSV中H、S、V分别代表什么
H:色相(Hue, H)
- 定义:颜色的基本类型(如红、绿、蓝)。
- 范围:0°–360°(环形色轮)。
0° = 红色
120° = 绿色
240° = 蓝色
360° = 回到红色
S:饱和度(Saturation, S)
- 定义:颜色的鲜艳程度(从灰度到纯色)。
- 范围:0%–100%
0% = 灰色(完全去色)
100% = 最鲜艳的颜色
V:明度(Value,V)
- 定义:颜色的亮度。明度越高,颜色越亮;越低则越暗。
- 范围:0%(纯黑)–100%(最亮,颜色保持纯色)。
V=100%:亮红色(RGB的红色通道全开)。
V=50%:暗红色(亮度减半)。
V=0%:纯黑色(所有颜色通道关闭)。
(三)、HSV和HSL的区别
模型 | 定义公式 | 几何意义 | 示例(纯红色) | 适用场景 | 核心优势 |
---|---|---|---|---|---|
HSV | V=max(R,G,B) | 颜色的最大亮度(最亮时颜色保持纯色) | V=100% → 纯红(RGB: 255,0,0) | 图像处理、快速调色 | 直观调整颜色亮度 |
HSL | L= (max+min)/2 | 颜色的平均亮度(中等亮度时颜色最纯) | L=50% → 纯红(RGB: 255,0,0) | 设计、数据可视化 | 自然保持颜色鲜艳度 |
(四)、HSV的圆柱模型
HSV还有单六棱锥模型,这里主要说圆柱模型
基本结构
HSV 圆柱模型由三个正交维度构成,分别对应色相(H)、饱和度(S)、明度(V):
-
色相(Hue)
- 几何方向:沿圆柱的 圆周分布,角度范围为 0°–360°。
- 物理意义:决定颜色的基本类型(如红、绿、蓝等)。
-
饱和度(Saturation)
- 几何方向:沿圆柱的 径向分布,范围 0%(中心)–100%(边缘)。
- 物理意义:表示颜色纯度(鲜艳程度)。
-
明度(Value)
- 几何方向:沿圆柱的 垂直轴分布,范围 0%(底部)–100%(顶部)。
- 物理意义:控制颜色亮度(明暗程度)。
关键几何特征
- 色相环的连续性
- 圆周闭合性:色相角度 0° 与 360° 重合,颜色从红→黄→绿→青→蓝→品红→红无缝过渡。
- 几何意义:圆柱的圆周方向形成闭环,确保颜色过渡无间断。
- 饱和度与径向距离
- 中心轴为灰度轴:当 S=0% 时,无论 H 和 V 如何,颜色均为不同明度的灰色(如深灰、浅灰)。
- 边缘为纯色:当 S=100% 时,颜色达到最大纯度,对应 RGB 的纯色(如红、绿、蓝)。
- 底部为纯黑(V=0%):所有颜色在 V=0% 时均变为黑色,与 H 和 S 无关。
- 顶部为最亮纯色(V=100%):颜色保持最大亮度,但可能因 S 不同呈现不同鲜艳度。
- 示例:
- V=100%、S=100% → 纯红色(RGB: 255,0,0)。
- V=100%、S=50% → 浅红色(RGB: 255,128,128)。
- 示例:
- 顶部为最亮纯色(V=100%):颜色保持最大亮度,但可能因 S 不同呈现不同鲜艳度。
- 颜色过渡规律
- 垂直方向(调整 V):
- 颜色亮度线性变化,但饱和度不变。
- 示例:V 从 50%→100%,颜色从暗红→亮红,但始终为红色(H 固定)。
- 径向方向(调整 S):
- 颜色从中心灰色逐渐变为边缘纯色。
- 示例:S 从 0%→100%,颜色从灰→浅红→纯红。
- 圆周方向(调整 H):
- 颜色种类周期性变化,色轮角度对应不同颜色类型。
- 示例:H 从 0°→60°,颜色从红→橙→黄。
- 垂直方向(调整 V):
(五)、十六进制转HSV
function hexToHsv(hex) {// 1. 移除#号并解析R, G, B分量(0~255)hex = hex.replace(/^#/, '');let r, g, b;if (hex.length === 3) {// 处理简写格式(如 #RGB → #RRGGBB)r = parseInt(hex[0] + hex[0], 16);g = parseInt(hex[1] + hex[1], 16);b = parseInt(hex[2] + hex[2], 16);} else {r = parseInt(hex.substring(0, 2), 16);g = parseInt(hex.substring(2, 4), 16);b = parseInt(hex.substring(4, 6), 16);}// 2. 归一化到0~1范围r /= 255, g /= 255, b /= 255;// 3. 计算最大值、最小值和色度(Chroma)const max = Math.max(r, g, b);const min = Math.min(r, g, b);const chroma = max - min;// 4. 计算明度(Value)const v = max;// 5. 计算饱和度(Saturation)let s = max === 0 ? 0 : chroma / max;// 6. 计算色相(Hue)let h = 0;if (chroma !== 0) {switch (max) {case r:h = ((g - b) / chroma) % 6;break;case g:h = (b - r) / chroma + 2;break;case b:h = (r - g) / chroma + 4;break;}h = (h * 60 + 360) % 360; // 确保角度在0~360之间}// 7. 转换为百分比并四舍五入return {h: Math.round(h),s: Math.round(s * 100),v: Math.round(v * 100)};
}
计算色度
const chroma = max - min;
原理和HSL一样,不再赘诉
计算明度
const v = max;
根据HSL模型定义,明度直接取最大值
计算饱和度
let s = max === 0 ? 0 : chroma / max;
为什么在计算饱和度时HSV和HSL两个模型公式不一样?
这源于两者对颜色亮度的定义差异以及几何模型的根本区别
HSV/HSL中对S公式理解
- HSV 的饱和度公式
- 物理意义:
- 饱和度是 色度(Chroma)占当前明度(V)的比例。
- 明度 V 是 RGB 的最大值,因此饱和度表示颜色纯度相对于最大亮度的占比。
- 纯红色(RGB(255,0,0)):V=1,Chroma=1→S=100%。
- 浅红色(RGB(255,128,128)):V=1,Chroma=0.5→S=50%。
- HSL 的饱和度公式
- 物理意义:
- 饱和度是 色度占当前亮度下可能的最大色度的比例。
- 分母 1−∣2L−1∣ 表示当前亮度 L 下允许的最大色度。
- 当 L=0.5(中等亮度)时,分母为 1,饱和度 S=Chroma
- 当 L→0 或 L→1(接近黑/白)时,分母趋近 0,饱和度被压缩。
计算色相
if (chroma !== 0) {switch (max) {case r:h = ((g - b) / chroma) % 6;break;case g:h = (b - r) / chroma + 2;break;case b:h = (r - g) / chroma + 4;break;}h = (h * 60 + 360) % 360; // 确保角度在0~360之间}
原理和HSL一样,不再赘诉
六、HSV转十六进制
function hsvToHex(h, s, v) {// 1. 规范化输入值h = ((h % 360) + 360) % 360; // 确保色相在0~360之间s = Math.max(0, Math.min(100, s)) / 100; // 饱和度转为0~1v = Math.max(0, Math.min(100, v)) / 100; // 明度转为0~1// 2. 处理饱和度为0的情况(灰度色)if (s === 0) {const gray = Math.round(v * 255);return `#${gray.toString(16).padStart(2, '0').repeat(3)}`;}// 3. 计算色度、中间值和明度偏移const c = v * s;const x = c * (1 - Math.abs(((h / 60) % 2) - 1));const m = v - c;// 4. 根据色相区间确定RGB初始值let r, g, b;if (h < 60) {[r, g, b] = [c, x, 0];} else if (h < 120) {[r, g, b] = [x, c, 0];} else if (h < 180) {[r, g, b] = [0, c, x];} else if (h < 240) {[r, g, b] = [0, x, c];} else if (h < 300) {[r, g, b] = [x, 0, c];} else {[r, g, b] = [c, 0, x];}// 5. 调整RGB值并转换为十六进制const toHex = (value) => {const hex = Math.round((value + m) * 255).toString(16);return hex.padStart(2, '0');};return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
}
计算色度
const c = v * s;
在HSV中为什么计算色度公式是v * s?
色度 c 是颜色在 RGB 空间中的最大分量与最小分量的差值,表示颜色的“纯度”或“鲜艳程度”。在 HSV 模型中:
- 当 S = 1 时,颜色为纯色,色度 c 达到最大值(c = V)。
- 当 S = 0 时,颜色为灰色,色度 c = 0。
- 因此,色度 c 是饱和度和明度的乘积:
c = V * S
计算中间值
const x = c * (1 - Math.abs(((h / 60) % 2) - 1));
这里和上面HSL转十六进制时求x理解一致(这是因为在十六进制转为HSL和十六进制转为HSV转换中对色相的处理方式完全相同)
明度偏移
const m = v - c;
为什么HSL或HSV转为十六进制 m 的计算方式不同?
HSV
- 在 RGB 中,max(R, G, B) = v(由 v 决定)
- min(R, G, B) = v - c(因为 c = max - min)。
- 所以 m 的作用是 确保 min(R, G, B) 正确,使得:
- 当 s = 1 时,c = v,m = 0(纯色,最小值是 0)。
- 当 s = 0 时,c = 0,m = v(灰度,所有分量等于 v)。
HSL
- 在 RGB 中,(max + min) / 2 = l(由 l 决定)。
- c = max - min(色度)。
- 所以 min = l - c / 2(因为 max = min + c,代入 (max + min)/2 = l 可得)。
- m 的作用是 确保 min(R, G, B) 正确,使得:
- 当 s = 1 且 l = 0.5 时,c = 1,m = 0.5 - 0.5 = 0(纯色)。
- 当 s = 0 时,c = 0,m = l(灰度,所有分量等于 l)。
参考文章
- 由RGB到HSV的转换详解
- 13 个 颜色转换 的高级方法🌈
- 3D空间点到直线的距离
- 漫步色彩空间:解锁HSV(HSB)的奥秘