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
),但无法计算出相应的数字。仅供参考,根据您在中的答案发布了最终解决方案