转换RGB到RGBA /白色。

时间:2022-08-10 00:21:03

I have a hex color, e.g. #F4F8FB (or rgb(244, 248, 251)) that I want converted into an as-transparent-as-possible rgba color (when displayed over white). Make sense? I'm looking for an algorithm, or at least idea of an algorithm for how to do so.

我有一个十六进制的颜色,例如F4F8FB(或rgb(244,248,251)),我想把它转换成尽可能透明的rgba颜色(当显示在白色上时)。有意义吗?我在寻找一种算法,或者至少是一种算法。

For Example:

例如:

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

Ideas?

想法吗?


FYI solution based on Guffa's answer:

FYI解决方案基于Guffa的回答:

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)' 
    }

7 个解决方案

#1


179  

Take the lowest color component, and convert that to an alpha value. Then scale the color components by subtracting the lowest, and dividing by the alpha value.

取最低的颜色分量,并将其转换为alpha值。然后用最小值减去最小值,然后除以alpha值。

Example:

例子:

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

So, rgb(152, 177, 202) displays as rgba(0, 62, 123, .404).

因此,rgb(152, 177, 202)显示为rgba(0, 62, 123, .404)。

I have verified in Photoshop that the colors actually match perfectly.

我已经在Photoshop中验证过,颜色确实匹配得很好。

#2


22  

Let r, g, and b be the input values and r', g', b', and a' be the output values, all scaled (for now, as it makes the math prettier) between 1 and 0. Then, by the formula for overlaying colors:

让r, g,和b是输入值,r', g', b'和a'是输出值,所有的缩放(现在,因为它使数学更漂亮)在1和0之间。然后,通过叠加颜色的公式:

r = a' * r' + 1 - a'
g = a' * g' + 1 - a'
b = a' * b' + 1 - a'

The 1 - a' terms represent the background contribution, and the other terms represent the foreground. Do some algebra:

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

Intuitively, it seems that the minimum color value will be the limiting factor in the problem, so bind this to m:

从直观上看,颜色的最小值似乎是问题的限制因素,所以将其绑定到m:

m = min(r, g, b)

Set the corresponding output value, m', to zero, as we want to maximize transparency:

设置相应的输出值m',为0,因为我们想最大化透明度:

0 = (m - 1) / a' + 1
-1 = (m - 1) / a'
-a' = m - 1
a' = 1 - m

So, in javascript (translating from 1 to 255 along the way):

在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];
}

Note that I'm assuming that a' is opacity here. It is trivial to change it to transparency - just remove the "1 -" from the formula for a'. Anothing thing to note is that this does not seem to produce exact results - it said that the opacity was 0.498 for the example you gave above (128, 128, 255). However, this is extremely close.

注意,我假设这里是不透明度。将它改为透明是很简单的——只需将“1”从“a”的公式中删除即可。要注意的是,这似乎并没有产生确切的结果——它说,你上面给出的例子的不透明度为0.498(128,128,255)。然而,这是非常接近的。

#3


6  

I'd look to RGB<->HSL conversion. I.e. luminosity == amount of white == amount of transparency.

我将查看RGB<->HSL转换。例如,亮度== =透明度的量。

For your example rgb( 128, 128, 255 ), we need to shift RGB values to 0 first by maximum amount, i.e. to rgb( 0, 0, 128 ) - that would be our color with as few of white as possible. And after that, using formula for luminance, we calculate amount of white we need to add to our dark color to get original color - that would be our alpha:

对于您的示例rgb(128、128、255),我们需要将rgb值按最大数量(即rgb(0,0, 128))转换为0,这将是我们的颜色,尽可能少的白色。然后,用亮度公式,我们计算出白色的量我们需要加到我们的暗颜色中来得到原始的颜色,那就是我们的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;

Hope that makes sense. :)

希望是有意义的。:)

#4


4  

For those of you using SASS/SCSS, I've wrote a small SCSS function so you can easily use the algorithm described by @Guffa

对于那些使用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
    );
}

#5


2  

I'm just describing an idea for the algorithm, no full solution:

我只是在描述一个算法的想法,没有完整的解决方案:

Basically, you have three numbers x, y, z and you are looking for three new numbers x', y', z' and a multiplier a in the range [0,1] such that:

基本上,你有三个数字x, y, z,你在寻找三个新的数字x', y', z'和一个乘数a在范围[0,1]中,这样:

x = a + (1 - a) x'
y = a + (1 - a) y'
z = a + (1 - a) z'

This is written in units where the channels also take values in the range [0,1]. In 8bit discrete values, it'd be something like this:

这是在通道也取值范围[0,1]的单元中编写的。在8位离散值中,它是这样的:

x = 255 a + (1 - a) x'
y = 255 a + (1 - a) y'
z = 255 a + (1 - a) z'

Moreover, you want the largest possible value a. You can solve:

而且,你想要最大的可能值a,你可以解:

a  = (x - x')/(255 - x')          x' = (x - 255 a)/(1 - a)

Etc. In real values this has infinitely many solutions, just plug in any real number a, but the problem is to find a number for which the discretization error is minimal.

等等,在实值中,这有无穷多个解,只要代入任意实数a,但问题是要找到一个离散化误差最小的数。

#6


0  

This should do it:

这应该这样做:

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

#7


-1  

The top answer didn't work for me with low color components. For example it does not calculate correct alpha if color is #80000. Technically it should make it into #ff0000 with alpha 0.5. To resolve this, you need to use RGB -> HSL -> RGBA conversion. This is pseudo code to get the correct values:

最上面的答案对我来说并不适用于低颜色的成分。例如,如果颜色是#80000,它不计算正确的alpha值。从技术上讲,它应该会变成#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" will contain the value of the new adjusted color and use "alpha" variable to control the transparency.

“newRgb”将包含新调整颜色的值,并使用“alpha”变量来控制透明度。

#1


179  

Take the lowest color component, and convert that to an alpha value. Then scale the color components by subtracting the lowest, and dividing by the alpha value.

取最低的颜色分量,并将其转换为alpha值。然后用最小值减去最小值,然后除以alpha值。

Example:

例子:

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

So, rgb(152, 177, 202) displays as rgba(0, 62, 123, .404).

因此,rgb(152, 177, 202)显示为rgba(0, 62, 123, .404)。

I have verified in Photoshop that the colors actually match perfectly.

我已经在Photoshop中验证过,颜色确实匹配得很好。

#2


22  

Let r, g, and b be the input values and r', g', b', and a' be the output values, all scaled (for now, as it makes the math prettier) between 1 and 0. Then, by the formula for overlaying colors:

让r, g,和b是输入值,r', g', b'和a'是输出值,所有的缩放(现在,因为它使数学更漂亮)在1和0之间。然后,通过叠加颜色的公式:

r = a' * r' + 1 - a'
g = a' * g' + 1 - a'
b = a' * b' + 1 - a'

The 1 - a' terms represent the background contribution, and the other terms represent the foreground. Do some algebra:

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

Intuitively, it seems that the minimum color value will be the limiting factor in the problem, so bind this to m:

从直观上看,颜色的最小值似乎是问题的限制因素,所以将其绑定到m:

m = min(r, g, b)

Set the corresponding output value, m', to zero, as we want to maximize transparency:

设置相应的输出值m',为0,因为我们想最大化透明度:

0 = (m - 1) / a' + 1
-1 = (m - 1) / a'
-a' = m - 1
a' = 1 - m

So, in javascript (translating from 1 to 255 along the way):

在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];
}

Note that I'm assuming that a' is opacity here. It is trivial to change it to transparency - just remove the "1 -" from the formula for a'. Anothing thing to note is that this does not seem to produce exact results - it said that the opacity was 0.498 for the example you gave above (128, 128, 255). However, this is extremely close.

注意,我假设这里是不透明度。将它改为透明是很简单的——只需将“1”从“a”的公式中删除即可。要注意的是,这似乎并没有产生确切的结果——它说,你上面给出的例子的不透明度为0.498(128,128,255)。然而,这是非常接近的。

#3


6  

I'd look to RGB<->HSL conversion. I.e. luminosity == amount of white == amount of transparency.

我将查看RGB<->HSL转换。例如,亮度== =透明度的量。

For your example rgb( 128, 128, 255 ), we need to shift RGB values to 0 first by maximum amount, i.e. to rgb( 0, 0, 128 ) - that would be our color with as few of white as possible. And after that, using formula for luminance, we calculate amount of white we need to add to our dark color to get original color - that would be our alpha:

对于您的示例rgb(128、128、255),我们需要将rgb值按最大数量(即rgb(0,0, 128))转换为0,这将是我们的颜色,尽可能少的白色。然后,用亮度公式,我们计算出白色的量我们需要加到我们的暗颜色中来得到原始的颜色,那就是我们的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;

Hope that makes sense. :)

希望是有意义的。:)

#4


4  

For those of you using SASS/SCSS, I've wrote a small SCSS function so you can easily use the algorithm described by @Guffa

对于那些使用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
    );
}

#5


2  

I'm just describing an idea for the algorithm, no full solution:

我只是在描述一个算法的想法,没有完整的解决方案:

Basically, you have three numbers x, y, z and you are looking for three new numbers x', y', z' and a multiplier a in the range [0,1] such that:

基本上,你有三个数字x, y, z,你在寻找三个新的数字x', y', z'和一个乘数a在范围[0,1]中,这样:

x = a + (1 - a) x'
y = a + (1 - a) y'
z = a + (1 - a) z'

This is written in units where the channels also take values in the range [0,1]. In 8bit discrete values, it'd be something like this:

这是在通道也取值范围[0,1]的单元中编写的。在8位离散值中,它是这样的:

x = 255 a + (1 - a) x'
y = 255 a + (1 - a) y'
z = 255 a + (1 - a) z'

Moreover, you want the largest possible value a. You can solve:

而且,你想要最大的可能值a,你可以解:

a  = (x - x')/(255 - x')          x' = (x - 255 a)/(1 - a)

Etc. In real values this has infinitely many solutions, just plug in any real number a, but the problem is to find a number for which the discretization error is minimal.

等等,在实值中,这有无穷多个解,只要代入任意实数a,但问题是要找到一个离散化误差最小的数。

#6


0  

This should do it:

这应该这样做:

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

#7


-1  

The top answer didn't work for me with low color components. For example it does not calculate correct alpha if color is #80000. Technically it should make it into #ff0000 with alpha 0.5. To resolve this, you need to use RGB -> HSL -> RGBA conversion. This is pseudo code to get the correct values:

最上面的答案对我来说并不适用于低颜色的成分。例如,如果颜色是#80000,它不计算正确的alpha值。从技术上讲,它应该会变成#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" will contain the value of the new adjusted color and use "alpha" variable to control the transparency.

“newRgb”将包含新调整颜色的值,并使用“alpha”变量来控制透明度。