将 RGB 转换为 RGBA 白色

发布于 2024-11-19 21:18:58 字数 1283 浏览 2 评论 0原文

我有一个十六进制颜色,例如 #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 答案的仅供参考的解决方案:

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

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.

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:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

清音悠歌 2024-11-26 21:18:59

取最低的颜色分量,并将其转换为 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)

我已经在 Photoshop 中验证了颜色确实完美匹配。

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.

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).

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

我很OK 2024-11-26 21:18:59

设 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):

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

请注意,我假设 a' 在这里是不透明度的。将其更改为透明度很简单 - 只需从 a' 的公式中删除“1 -”即可。需要注意的另一件事是,这似乎不会产生准确的结果 - 它表示上面给出的示例的不透明度为 0.498 (128, 128, 255)。然而,这已经非常接近了。

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 = 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:

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 = min(r, g, b)

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

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):

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.

梦晓ヶ微光ヅ倾城 2024-11-26 21:18:59

我会考虑 RGB<->HSL 转换。即发光度==白色量==透明度量。

对于您的示例 rgb( 128, 128, 255 ),我们需要首先将 RGB 值移动到 0 最大量,即 rgb( 0, 0, 128 ) - 这将是我们的颜色,其中白色尽可能少。之后,使用亮度公式,我们计算需要添加到深色中以获得原始颜色的白色量 - 这将是我们的 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;

希望这是有道理的。 :)

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

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:

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. :)

‖放下 2024-11-26 21:18:59

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

For those of you using SASS/SCSS, I've wrote a small SCSS function so you can easily use the algorithm described by @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
    );
}
尹雨沫 2024-11-26 21:18:59

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

基本上,你有三个数字 xyz 并且你是寻找 [0 范围内的三个新数字 x'y'z' 和乘数 a ,1] 这样:

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)

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

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 = 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:

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  = (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.

你的背包 2024-11-26 21:18:59

这应该可以做到:

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

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
你爱我像她 2024-11-26 21:18:59

对于低颜色成分,最重要的答案对我不起作用。例如,如果颜色为#80000,则它不会计算正确的 alpha。从技术上讲,它应该使其成为 alpha 0.5 的#ff0000。要解决这个问题,您需要使用 RGB ->福胜利-> 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”变量来控制透明度。

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:

//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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文