如何将PSD解析出的浮点颜色对象转换为可用RGBA值
问题解析与解决方案
我在解析PSD文件的vectorStrokeContent颜色时,拿到了一组异常的浮点RGB值,超出了常规0-1的范围:
{ "red": 1.0343483686447144, "green": 0.9487225413322449, "blue": -0.12634865939617157, "alpha": 100, "rgba": "rgba(1.0343483686447144, 0.9487225413322449, -0.12634865939617157, 1)" }
实际这个颜色是黄色,后来发现这组值其实是LAB颜色空间的参数(对应lab(94 -12 103)),用CSS的lab()属性可以正常显示,但业务需要转成标准RGBA值,以下是完整的LAB转RGBA计算方案:
LAB转RGBA的完整计算步骤
LAB转RGBA需要经过两次转换:LAB → XYZ → sRGB,默认基于sRGB标准的D65白点(X=95.047, Y=100.000, Z=108.883)。
1. LAB转XYZ
function labToXYZ(L, a, b) { // 归一化LAB参数 const fy = (L + 16) / 116; const fx = a / 500 + fy; const fz = fy - b / 200; // 计算XYZ线性值 const x = fx ** 3 > 0.008856 ? fx ** 3 : (fx - 16/116) / 7.787; const y = fy ** 3 > 0.008856 ? fy ** 3 : (fy - 16/116) / 7.787; const z = fz ** 3 > 0.008856 ? fz ** 3 : (fz - 16/116) / 7.787; // 乘以D65白点值 return { X: x * 95.047, Y: y * 100.000, Z: z * 108.883 }; }
2. XYZ转sRGB
function xyzToSRGB(X, Y, Z) { // 归一化到0-1范围 const x = X / 100; const y = Y / 100; const z = Z / 100; // 计算线性RGB值 let R = 3.2406 * x - 1.5372 * y - 0.4986 * z; let G = -0.9689 * x + 1.8758 * y + 0.0415 * z; let B = 0.0557 * x - 0.2040 * y + 1.0570 * z; // 伽马校正(sRGB标准) const gammaCorrect = (val) => { return val > 0.0031308 ? 1.055 * Math.pow(val, 1/2.4) - 0.055 : 12.92 * val; }; R = gammaCorrect(R); G = gammaCorrect(G); B = gammaCorrect(B); // 限制在0-1范围,转成0-255整数 return { r: Math.max(0, Math.min(255, Math.round(R * 255))), g: Math.max(0, Math.min(255, Math.round(G * 255))), b: Math.max(0, Math.min(255, Math.round(B * 255))) }; }
3. 组合成LAB转RGBA函数
function labToRGBA(L, a, b, alpha = 100) { const { X, Y, Z } = labToXYZ(L, a, b); const { r, g, b } = xyzToSRGB(X, Y, Z); const alphaNormalized = alpha / 100; return { red: r, green: g, blue: b, alpha: alpha, rgba: `rgba(${r}, ${g}, ${b}, ${alphaNormalized})` }; }
适配你的解析函数的修改建议
你的原函数误将LAB参数当成了RGB值,需要先判断颜色类型(PSD中LAB颜色的class id通常是'LbCl'),再选择对应的处理逻辑:
function getRGBColor(color, opacity = 100) { if ("Clr " in color) { color = color["Clr "]; } const type = color.class.id; // 处理LAB颜色 if (type === 'LbCl') { const L = color["L "]; // 对应lab的L值(0-100) const a = color["a "]; // 对应lab的a值(-128~127) const b = color["b "]; // 对应lab的b值(-128~127) return labToRGBA(L, a, b, opacity); } // 处理常规RGB颜色 let red = color["Rd "]; let green = color["Grn "]; let blue = color["Bl "]; if ("blueFloat" in color) { red = color.redFloat; green = color.greenFloat; blue = color.blueFloat; } // 确保RGB值在0-1范围(如果是浮点型) red = Math.max(0, Math.min(1, red)); green = Math.max(0, Math.min(1, green)); blue = Math.max(0, Math.min(1, blue)); // 转成0-255整数 const r = Math.round(red * 255); const g = Math.round(green * 255); const b = Math.round(blue * 255); const alphaNormalized = opacity / 100; return { red: r, green: g, blue: b, alpha: opacity, rgba: `rgba(${r}, ${g}, ${b}, ${alphaNormalized})` }; }
测试你的例子:lab(94 -12 103)转RGBA后会得到rgba(255, 239, 0, 1),也就是标准的黄色,符合预期。
内容的提问来源于stack exchange,提问作者1.21 gigawatts
相关产品推荐
相关产品推荐

