颜色转换
HEX 转 RGB
ts
/**
* HEX 转 RGB
* @param hex - HEX 颜色值,支持 #RGB、#RRGGBB 格式
* @returns RGB 颜色对象
*/
export function hexToRgb(hex: string) {
// 移除 # 前缀
const normalizedHex = hex.replace('#', '')
// 处理 #RGB 格式(简写)
if (normalizedHex.length === 3) {
const r = parseInt(normalizedHex[0] + normalizedHex[0], 16)
const g = parseInt(normalizedHex[1] + normalizedHex[1], 16)
const b = parseInt(normalizedHex[2] + normalizedHex[2], 16)
return { r, g, b }
}
// 处理 #RRGGBB 格式
else if (normalizedHex.length === 6) {
const r = parseInt(normalizedHex.substring(0, 2), 16)
const g = parseInt(normalizedHex.substring(2, 4), 16)
const b = parseInt(normalizedHex.substring(4, 6), 16)
return { r, g, b }
}
// 无效格式
else {
throw new Error(`Invalid HEX color format: ${hex}`)
}
}HEX 转 HSL
ts
import { hexToRgb } from './hex-to-rgb'
import { rgbToHsl } from './rgb-to-hsl'
/**
* HEX 转 HSL
* @param hex - HEX 颜色值,支持 #RGB、#RRGGBB 格式
* @returns HSL 颜色对象
*/
export function hexToHsl(hex: string) {
const rgb = hexToRgb(hex)
return rgbToHsl(rgb)
}RGB 转 HEX
ts
/**
* RGB 转 HEX
* @param rgb - RGB 颜色对象
* @returns HEX 颜色值字符串,格式为 #RRGGBB
*/
export function rgbToHex(rgb: { r: number; g: number; b: number }) {
const { r, g, b } = rgb
// 确保值在 0-255 范围内
const clamp = (value: number) => Math.max(0, Math.min(255, Math.round(value)))
// 转换为十六进制字符串并补零
const toHex = (value: number) => {
const hex = clamp(value).toString(16)
return hex.length === 1 ? '0' + hex : hex
}
return `#${toHex(r)}${toHex(g)}${toHex(b)}`
}RGB 转 HSL
ts
/**
* RGB 转 HSL
*/
export function rgbToHsl(rgb: { r: number; g: number; b: number }) {
const { r, g, b } = rgb
// 归一化
const rNorm = r / 255
const gNorm = g / 255
const bNorm = b / 255
// 最大值、最小值、差值
const max = Math.max(rNorm, gNorm, bNorm)
const min = Math.min(rNorm, gNorm, bNorm)
const delta = max - min
// 亮度 L
const l = (max + min) / 2
// 饱和度 S
let s = 0
if (delta !== 0) {
s = delta / (1 - Math.abs(2 * l - 1))
}
// 色相 H
let h = 0
if (delta !== 0) {
if (rNorm >= gNorm && rNorm >= bNorm) {
h = ((gNorm - bNorm) / delta) % 6
} else if (gNorm >= bNorm) {
h = (bNorm - rNorm) / delta + 2
} else {
h = (rNorm - gNorm) / delta + 4
}
h *= 60
if (h < 0) h += 360
}
// 返回整数格式
return {
h: Math.round(h),
s: Math.round(s * 100),
l: Math.round(l * 100),
}
}HSL 转 RGB
ts
/**
* HSL 转 RGB
*/
export function hslToRgb(hsl: { h: number; s: number; l: number }) {
const { h, s, l } = hsl
// 归一化 HSL 值
const H = h / 60 // 将 0~360 转换为 0~6
const S = s / 100
const L = l / 100
// 计算中间值
const C = (1 - Math.abs(2 * L - 1)) * S
const X = C * (1 - Math.abs((H % 2) - 1))
const m = L - C / 2
// 根据 H 的区间确定 RGB 分量
let r, g, b
if (H >= 0 && H < 1) {
r = C
g = X
b = 0
} else if (H >= 1 && H < 2) {
r = X
g = C
b = 0
} else if (H >= 2 && H < 3) {
r = 0
g = C
b = X
} else if (H >= 3 && H < 4) {
r = 0
g = X
b = C
} else if (H >= 4 && H < 5) {
r = X
g = 0
b = C
} else if (H >= 5 && H < 6) {
r = C
g = 0
b = X
} else {
// 处理 H = 360 的情况(即 H = 0)
r = 0
g = 0
b = 0
}
// 应用偏移量 m,转换为 0~1 范围
r += m
g += m
b += m
// 转换为 0~255 的整数范围
return {
r: Math.round(r * 255),
g: Math.round(g * 255),
b: Math.round(b * 255),
}
}HSL 转 HEX
ts
import { hslToRgb } from './hsl-to-rgb'
import { rgbToHex } from './rgb-to-hex'
/**
* HSL 转 HEX
* @param hsl - HSL 颜色对象
* @returns HEX 颜色值字符串,格式为 #RRGGBB
*/
export function hslToHex(hsl: { h: number; s: number; l: number }) {
const rgb = hslToRgb(hsl)
return rgbToHex(rgb)
}