Javascript 将RGB转换为白色上的RGBA

Javascript 将RGB转换为白色上的RGBA,javascript,colors,css,rgba,Javascript,Colors,Css,Rgba,我有一个十六进制颜色,例如#F4F8FB(或rgb(244、248、251)),我希望将其转换为尽可能透明的rgba颜色(在白色上显示时)。有道理?我在寻找一个算法,或者至少是一个如何实现的算法的想法 例如: rgb( 128, 128, 255 ) --> rgba( 0, 0, 255, .5 ) rgb( 152, 177, 202 ) --> rgba( 50, 100, 150, .5 ) // can be better(lower alpha) 想法

我有一个十六进制颜色,例如
#F4F8FB
(或
rgb(244、248、251)
),我希望将其转换为尽可能透明的rgba颜色(在白色上显示时)。有道理?我在寻找一个算法,或者至少是一个如何实现的算法的想法

例如:

rgb( 128, 128, 255 ) --> rgba(   0,   0, 255,  .5 )
rgb( 152, 177, 202 ) --> rgba(  50, 100, 150,  .5 ) // can be better(lower alpha)
想法


基于Guffa回答的供参考的解决方案:

函数RGBtoRGBA(r,g,b){ 如果((g==null)和&(typeof r==string')){ var hex=r.replace(/^\s*| |\s*$/g,'); 如果(十六进制长度===3){ 十六进制=十六进制替换(/()/g,$1$1'); } r=parseInt(十六进制substr(0,2,16); g=parseInt(十六进制substr(2,2,16); b=parseInt(十六进制substr(4,2,16); } var min,a=(255-(min=Math.min(r,g,b))/255; 返回{ 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(204153102)=RGBtoRGBA('#CC9966')==RGBtoRGBA('C96')== { r:170, g:85, b:0, a:0.6, rgba:'rgba(170,85,0,0.6)' }
我只是描述算法的一个想法,没有完整的解决方案:

基本上,您有三个数字
x
y
z
,您正在寻找三个新数字
x'
y'
z'
,以及[0,1]范围内的乘法器
a
,以便:

x=a+(1-a)x'
y=a+(1-a)y'
z=a+(1-a)z'
这是以通道也采用[0,1]范围内的值的单位写入的。在8位离散值中,应该是这样的:

x=255a+(1-a)x'
y=255 a+(1-a)y'
z=255 a+(1-a)z'
此外,您需要尽可能大的值
a
。您可以解决以下问题:

a=(x-x')/(255-x')x'=(x-255a)/(1-a)
等等。在实数中,这有无限多个解,只需插入任意实数
a
,但问题是找到离散化误差最小的数字。

这应该可以做到:

let x = min(r,g,b)
a = 1 - x/255                    # Correction 1
r,g,b = ( (r,g,b) - x ) / a      # Correction 2

取最低颜色分量,并将其转换为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(152177202)
显示为
rgba(0,62123,404)

我已经在Photoshop中验证了颜色实际上是完美匹配的。

我希望进行RGBHSL转换。即光度==白色量==透明度量

对于您的示例,
rgb(128128255)
,我们需要首先将rgb值按最大值移动到
0
,即移动到
rgb(0,0128)
——这将是我们的颜色,尽可能少的白色。然后,使用亮度公式,我们计算出需要添加到深色中的白色量,以获得原始颜色-这就是我们的alpha:

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;

希望这是有道理的

设r、g和b为输入值,r',g',b'和a'为输出值,所有值都在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):

函数rgba(r,g,b){
VarA=1-Math.min(r,Math.min(g,b))/255;
返回[255+(r-255)/a,255+(g-255)/a,255+(b-255)/a,a];
}

注意,我假设a'在这里是不透明的。将其更改为透明度很简单-只需从a'的公式中删除“1-”。另一件需要注意的事情是,这似乎并没有产生精确的结果——上面的例子(128128255)的不透明度是0.498。然而,这一点非常接近。

对于低颜色组件,上面的答案不适用于我。例如,如果颜色为#80000,它不会计算正确的alpha。从技术上讲,它应该以0.5的alpha值成为#ff0000。要解决此问题,您需要使用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”变量控制透明度。

对于使用SASS/SCSS的用户,我编写了一个小的SCSS函数,以便您可以轻松使用@Guffa描述的算法

@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
    );
}

中间人!你仍然希望它是可见的,不是完全透明的吗?有趣的问题!可能有一个完全相反的问题help@Mrchief-是的,我希望在白色上显示时颜色看起来相同,但尽可能透明。好问题,我一直想知道如何做到这一点,但通常会回避;)+1@e100-引发这一问题的具体问题是。基本上,我希望能够通过在所有元素的顶部放置阴影元素,在元素的顶部覆盖CSS阴影,而不阻止点击。我也想这样做一段时间,这样我就可以做一些随机的事情,比如:。另外,我发现这是一个有趣的问题:)谢谢!我也在做类似的事情(例如get
.404
),但无法计算出相应的数字。仅供参考,根据您在中的答案发布了最终解决方案