【问题标题】:Convert RGB to RGBA over white在白色上将 RGB 转换为 RGBA
【发布时间】:2011-10-04 01:58:35
【问题描述】:

我有一个十六进制颜色,例如#F4F8FB(或rgb(244, 248, 251)),我想将其转换为 as-transparent-as-possible 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)' 
    }

【问题讨论】:

  • 有趣!您仍然希望它正确可见,而不是完全透明?
  • 有趣的问题! stackoverflow.com/questions/2049230/convert-rgba-color-to-rgb 有一个完全相反的问题,它可能会有所帮助
  • @Mrchief - 是的,我希望颜色在显示为白色时看起来相同,但尽可能透明。
  • 好问题,我一直想知道如何做到这一点,但通常会回避它;)+1
  • @e100 - 触发此问题的具体问题是stackoverflow.com/questions/6658350/…。基本上,我希望能够通过将阴影元素放在所有内容之上,从而能够在具有背景颜色的元素之上覆盖 CSS 阴影,而不会阻止点击。我也想这样做一段时间,所以我可以做一些随机的事情,比如:jsfiddle.net/qwySW/2。另外,我发现这是一个有趣的问题:)

标签: javascript colors css rgba


【解决方案1】:

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

基本上,您有三个数字xyz,并且您正在寻找三个新数字x'y'z' 和一个乘数a,范围为[0 ,1] 这样:

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

这是以通道也采用 [0,1] 范围内的值的单位编写的。在 8bit 离散值中,它会是这样的:

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,但问题是要找到一个离散化误差最小的数。

【讨论】:

    【解决方案2】:

    应该这样做:

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

    【讨论】:

    • 我实际上只是注意到我在 alpha calc 中有一个错误(现在已修复)。所以这也可能与它有关。
    • 您的y(y-x) 仍然存在问题。 255 / (y-x) 错误地将最大数字强制为 255,因此您总是会得到一个 0、一个 255,然后是另一个数字:0, 22, 255255, 0, 55 等...
    • 我明白了,所以它不允许使用更深的颜色...我应该将其设为 /a 然后它匹配正确的答案。
    【解决方案3】:

    取最低的颜色分量,并将其转换为 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 中验证了颜色实际上完全匹配。

    【讨论】:

    • 谢谢!我正在做类似的事情(例如获取.404),但无法完全计算出数字。
    • 仅供参考,根据您的问题答案发布最终解决方案
    • @templatetypedef:将最低分量转换为 alpha 是从范围 0..255 缩放到 0..1,并反转。使用1.0 - 152 / 255 也可以。转换颜色分量只是从n..255 缩放到0..255,其中n 是最低的分量。
    • @Christoph:原理相同,但更复杂。除了使用最低的组件来计算 alpha,您还可以为每个组件计算可能的最低 alpha(即,当使用 0 或 255 作为组件值时,使用什么 alpha 值来获得正确的颜色),然后使用最高的这些阿尔法值。从中,您可以计算每个具有该 alpha 值的组件使用的颜色值,以获得正确的颜色。请注意,某些颜色组合(例如黑色背景上的白色)会将 1.0 作为可能使用的最低 alpha 值。
    • 我写了一个小小提琴来实现这个解决方案。链接在这里。 jsfiddle.net/wb5fwLoc/1。也许你们中的一个人可以使用它。这只是一个快速的,不是没有错误的脚本。它应该足够好玩了。
    【解决方案4】:

    我会考虑 RGBHSL 转换。 IE。亮度 == 白色的量 == 透明度的量。

    对于您的示例 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;
    

    希望这是有道理的。 :)

    【讨论】:

      【解决方案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
      

      直觉上,最小颜色值似乎会成为问题的限制因素,所以将 this 绑定到 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 -”。需要注意的一点是,这似乎不会产生确切的结果 - 它说对于您上面给出的示例(128、128、255),不透明度为 0.498。但是,这非常接近。

      【讨论】:

      • 如果您将乘积的 255 分配到等式中,您会得到正确的结果 - [255 * (r/255 - 1) / a + 1 * 255, ...] == [(255*r/255 - 255 * 1) / a + 255, ...] == [(r - 255) / a + 255, ...]
      【解决方案6】:

      对于低颜色组件,最佳答案对我不起作用。例如,如果颜色为#80000,它不会计算正确的 alpha。从技术上讲,它应该以 alpha 0.5 进入 #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”变量来控制透明度。

      【讨论】:

      • #800000rgba( 255, 0, 0, .5 ) 的颜色相差不大。第一个是深红色,第二个是鲑鱼色。除非显示为黑色,否则我认为它们是相同的。
      【解决方案7】:

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

      【讨论】:

        猜你喜欢
        • 2011-01-04
        • 2012-04-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-09-17
        相关资源
        最近更新 更多