将RGB转换为RGBA白色
我有一个hex颜色,例如#F4F8FB
(或rgb(244, 248, 251)
#F4F8FB
rgb(244, 248, 251)
),我想要转换为尽可能透明的 rgba颜色(白色显示时)。 合理? 我正在寻找一个algorithm,或者至less想法如何这样做的algorithm。
例如:
rgb( 128, 128, 255 ) --> rgba( 0, 0, 255, .5 ) rgb( 152, 177, 202 ) --> rgba( 50, 100, 150, .5 ) // can be better(lower alpha)
想法?
基于Guffa答案的FYI解决scheme:
function RGBtoRGBA(r, g, b){ if((g == null) && (typeof r === 'string')){ var hex = r.replace(/^\s*#|\s*$/g, ''); if(hex.length === 3){ hex = hex.replace(/(.)/g, '$1$1'); } r = parseInt(hex.substr(0, 2), 16); g = parseInt(hex.substr(2, 2), 16); b = parseInt(hex.substr(4, 2), 16); } var min, a = (255 - (min = Math.min(r, g, b))) / 255; return { r : r = 0|(r - min) / a, g : g = 0|(g - min) / a, b : b = 0|(b - min) / a, a : a = (0|1000*a)/1000, rgba : 'rgba(' + r + ', ' + g + ', ' + b + ', ' + a + ')' }; } RGBtoRGBA(204, 153, 102) == RGBtoRGBA('#CC9966') == RGBtoRGBA('C96') == { r : 170, g : 85 , b : 0 , a : 0.6, rgba : 'rgba(170, 85, 0, 0.6)' }
取最低的颜色分量,并将其转换为alpha值。 然后通过减去最小值和除以alpha值来缩放颜色分量。
例:
152 converts to an alpha value of (255 - 152) / 255 ~ 0.404 152 scales using (152 - 152) / 0.404 = 0 177 scales using (177 - 152) / 0.404 ~ 62 202 scales using (202 - 152) / 0.404 ~ 123
所以, rgb(152, 177, 202)
rgba(0, 62, 123, .404)
rgb(152, 177, 202)
显示为rgba(0, 62, 123, .404)
。
我已经在Photoshop中validation,颜色实际上匹配完美。
令r,g和b为input值,r',g',b'和a'为输出值,所有的比例(现在,因为它使math更美好)在1和0之间。覆盖颜色的公式:
r = a' * r' + 1 - a' g = a' * g' + 1 - a' b = a' * b' + 1 - a'
1 – a'项代表背景贡献,其他项代表前景。 做一些代数:
r = a' * (r' - 1) + 1 r - 1 = a' * (r' - 1) (r - 1) / (r' - 1) = a' (r' - 1) / (r - 1) = 1 / a' r' - 1 = (r - 1) / a' r' = (r - 1) / a' + 1
直观地看,最小颜色值似乎是问题的限制因素,所以把它绑定到m:
m = min(r, g, b)
将相应的输出值m'设置为零,因为我们想要最大化透明度:
0 = (m - 1) / a' + 1 -1 = (m - 1) / a' -a' = m - 1 a' = 1 - m
所以,在JavaScript(沿途翻译从1到255):
function rgba(r, g, b) { var a = 1 - Math.min(r, Math.min(g, b)) / 255; return [255 + (r - 255) / a, 255 + (g - 255) / a, 255 + (b - 255) / a, a]; }
请注意,我假设这里是“不透明”。 将它改为透明度是微不足道的,只需从公式中删除“1”即可。 要注意的是,这似乎并不能产生确切的结果 – 它说,上面给出的例子(128,128,255)的不透明度是0.498。 但是,这是非常接近的。
我期待RGB < – > HSL转换。 即亮度==白色的数量==透明度。
对于你的例子rgb( 128, 128, 255 )
,我们需要把RGB值先移动到最大值0
,即rgb( 0, 0, 128 )
– 这将是我们的颜色尽可能less的白色。 然后,使用公式的亮度,我们计算白色的数量,我们需要添加到我们的深色获得原来的颜色 – 这将是我们的阿尔法:
L = (MAX(R,G,B) + MIN(R,G,B))/2 L1 = (255 + 128) / 2 = 191.5 L2 = (128 + 0) /2 = 64 A = (191,5 - 64) / 255 = 0,5;
希望是有道理的。 🙂
对于那些使用SASS / SCSS的人,我已经写了一个小的SCSS函数,所以你可以很容易地使用@Guffa描述的algorithm
@function transparentize-on-white($color) { $red: red($color); $green: green($color); $blue: blue($color); $lowestColorComponent: min($red, $green, $blue); $alpha: (255 - $lowestColorComponent) / 255; @return rgba( ($red - $lowestColorComponent) / $alpha, ($green - $lowestColorComponent) / $alpha, ($blue - $lowestColorComponent) / $alpha, $alpha ); }
我只是描述了algorithm的一个想法,没有完整的解决scheme:
基本上,你有三个数字x
, y
, z
,你正在寻找三个新的数字x'
, y'
, z'
和a
在[0,1]范围内的乘数a
,
x = a + (1 - a) x' y = a + (1 - a) y' z = a + (1 - a) z'
这是写入通道也取值范围[0,1]的单位。 在8位离散值中,它会是这样的:
x = 255 a + (1 - a) x' y = 255 a + (1 - a) y' z = 255 a + (1 - a) z'
而且,你想要最大的可能值a
。 你可以解决:
a = (x - x')/(255 - x') x' = (x - 255 a)/(1 - a)
等等在实际价值中,这有无限多的解决scheme,只需插入任何实数a
,但问题是要find离散化误差最小的数字。
这应该做到这一点:
let x = min(r,g,b) a = 1 - x/255 # Correction 1 r,g,b = ( (r,g,b) - x ) / a # Correction 2
最好的答案不适用于低颜色成分的我。 例如,如果颜色是#80000,它不计算正确的阿尔法。 从技术上讲,它应该成为#ff0000 alpha 0.5。 要解决这个问题,你需要使用RGB – > HSL – > RGBA转换。 这是获取正确值的伪代码:
//Convert RGB to HSL hsl = new HSL(rgb) //Use lightness as alpha alpha = hsl.Lightness //For #80000 lightness is 0.5, so we have to take this into account. //Lightness more than 0.5 converts to alpha 1 and below is a linear ratio if (alpha > 0.5) { alpha = 1; } else { alpha = alpha / 0.5; //We need to drop the lightness of the color to 0.5 to get the actual color //that needs to display. Alpha blending will take care of that. hsl.Lightness = 0.5; } newRgb = hsl.convertToRgb()
“newRgb”将包含新调整颜色的值,并使用“alpha”variables来控制透明度。