cut / BeadQR /miniprogram /utils /color.js
Ethscriptions's picture
上传 BeadQR 微信小程序项目源码
9de7b70 verified
Raw History Blame Contribute Delete
1.86 kB
// 颜色基础:HEX/RGB 转换、OKLab 感知色彩空间、亮度
// OKLab 比 RGB 欧氏距离更接近人眼感受,配色更自然;距离统一放大 100 倍便于调参
function hexToRgb(hex) {
const value = String(hex || '').replace('#', '')
const full = value.length === 3 ? value.split('').map((c) => c + c).join('') : value
const num = parseInt(full, 16) || 0
return [(num >> 16) & 255, (num >> 8) & 255, num & 255]
}
function rgbToHex(r, g, b) {
const h = (v) => Math.max(0, Math.min(255, Math.round(v))).toString(16).padStart(2, '0')
return `#${h(r)}${h(g)}${h(b)}`
}
// sRGB 伽马解码查表,避免每次调用 Math.pow
const SRGB_TO_LINEAR = new Float32Array(256)
for (let i = 0; i < 256; i += 1) {
const c = i / 255
SRGB_TO_LINEAR[i] = c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4)
}
// 写入 out[offset..offset+2](L, a, b,均 ×100)
function rgbToOklabInto(r, g, b, out, offset) {
const lr = SRGB_TO_LINEAR[r]
const lg = SRGB_TO_LINEAR[g]
const lb = SRGB_TO_LINEAR[b]
const l = Math.cbrt(0.4122214708 * lr + 0.5363325363 * lg + 0.0514459929 * lb)
const m = Math.cbrt(0.2119034982 * lr + 0.6806995451 * lg + 0.1073969566 * lb)
const s = Math.cbrt(0.0883024619 * lr + 0.2817188376 * lg + 0.6299787005 * lb)
out[offset] = (0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s) * 100
out[offset + 1] = (1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s) * 100
out[offset + 2] = (0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s) * 100
}
// 感知亮度(与旧版一致的 Rec.601 加权,0~1),用于二维码深/浅模块约束
function luma(r, g, b) {
return (r * 0.299 + g * 0.587 + b * 0.114) / 255
}
function lumaHex(hex) {
const [r, g, b] = hexToRgb(hex)
return luma(r, g, b)
}
module.exports = { hexToRgb, rgbToHex, rgbToOklabInto, luma, lumaHex }