【问题标题】:JavaScript Calculate brighter colourJavaScript 计算更亮的颜色
【发布时间】:2011-09-20 14:25:57
【问题描述】:

我在 JS 中有一个颜色值作为字符串

#ff0000

我将如何以编程方式计算这种颜色的更亮/更亮版本,例如#ff4848,并能够通过百分比计算亮度,例如

increase_brightness('#ff0000', 50); // would make it 50% brighter

【问题讨论】:

  • 如果希望在一个或多个颜色通道饱和后能够再次降低亮度,记得保存原始颜色!

标签: javascript colors increment brightness


【解决方案1】:
function increase_brightness(hex, percent){
    // strip the leading # if it's there
    hex = hex.replace(/^\s*#|\s*$/g, '');

    // convert 3 char codes --> 6, e.g. `E0F` --> `EE00FF`
    if(hex.length == 3){
        hex = hex.replace(/(.)/g, '$1$1');
    }

    var r = parseInt(hex.substr(0, 2), 16),
        g = parseInt(hex.substr(2, 2), 16),
        b = parseInt(hex.substr(4, 2), 16);

    return '#' +
       ((0|(1<<8) + r + (256 - r) * percent / 100).toString(16)).substr(1) +
       ((0|(1<<8) + g + (256 - g) * percent / 100).toString(16)).substr(1) +
       ((0|(1<<8) + b + (256 - b) * percent / 100).toString(16)).substr(1);
}

/**
 * ('#000000', 50) --> #808080
 * ('#EEEEEE', 25) --> #F2F2F2
 * ('EEE     , 25) --> #F2F2F2
 **/

【讨论】:

  • 我从未使用过 JavaScript 的位运算符或任何语言的真正位运算符。我之前在 SO 上的解决方案中看到过它们,但我决定今天用谷歌搜索它们,以了解它们的用途和用途。我现在明白他们是为了修改数字的二进制表示。我想它可以让你做一些否则会很棘手的计算。我的问题是,为什么您的解决方案需要 (1
  • @WesleyJohnson - 是的,我可以很容易地写256,但它的函数是让第9位成为1,所以1&lt;&lt;8 合乎逻辑。基本上没有那块,如果剩下的计算结果是5,你最终会得到(5).toString(16),也就是5。因为我需要它是 2 个字符长,所以 1&lt;&lt;8 使它成为 105,我可以将 1 切掉以得到 05。现在是 1&lt;&lt;8 而不是 256 的原因:如果我需要它是 4 个字符长,我可以输入 1&lt;&lt;161&lt;&lt;24 6 个字符,(1&lt;&lt;24)*(1&lt;&lt;8) 8 个字符,等等...
  • 并且仅供参考:0| 是为了降低价值。它的功能等同于Math.floor(...)
  • 我非常感谢您的解释。我将不得不研究代码并玩弄这些运算符和概念......双关语。 :P
  • 伟大的工作,非常感谢!有没有机会,可以对 Hue 或类似 HSB 的转换做类似的事情?
【解决方案2】:

首先快速了解hex color codes

那么应该很容易将您的颜色值分解为 RGB,进行调整,然后返回新的颜色代码。

【讨论】:

    【解决方案3】:
    // color is a hex color like #aaaaaa and percent is a float, 1.00=100%
    // increasing a color by 50% means a percent value of 1.5
    function brighten(color, percent) {
        var r=parseInt(color.substr(1,2),16);
        var g=parseInt(color.substr(3,2),16);
        var b=parseInt(color.substr(5,2),16);
    
        return '#'+
           Math.min(255,Math.floor(r*percent)).toString(16)+
           Math.min(255,Math.floor(g*percent)).toString(16)+
           Math.min(255,Math.floor(b*percent)).toString(16);
    }
    

    现场样例:http://jsfiddle.net/emM55/

    【讨论】:

    • 另外,逻辑错了。 “brighten by 50%”实际上意味着“让 50% 接近白色”。按照你的逻辑,任何低于 128 的东西都不够饱和,任何超过 128 的东西都太饱和了,任何超过 170 的东西都变得 100% 饱和
    【解决方案4】:

    更新

    @zyklus 的回答更简单,效果也一样。仅当您对 RGB 和 HSL 之间的转换感兴趣时,请参考此答案。


    设置RGB的亮度:

    1. 将 RGB 转换为 HSL

    2. 设置HSL的亮度

    3. 从 HSL 转换回 RGB

    此链接曾经有将 RGB 转换为 HSL 和反向的代码: http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript

    /**
     * Converts an RGB color value to HSL. Conversion formula
     * adapted from http://en.wikipedia.org/wiki/HSL_color_space.
     * Assumes r, g, and b are contained in the set [0, 255] and
     * returns h, s, and l in the set [0, 1].
     *
     * @param   Number  r       The red color value
     * @param   Number  g       The green color value
     * @param   Number  b       The blue color value
     * @return  Array           The HSL representation
     */
    function rgbToHsl(r, g, b){
        r /= 255, g /= 255, b /= 255;
        var max = Math.max(r, g, b), min = Math.min(r, g, b);
        var h, s, l = (max + min) / 2;
    
        if(max == min){
            h = s = 0; // achromatic
        }else{
            var d = max - min;
            s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
            switch(max){
                case r: h = (g - b) / d + (g < b ? 6 : 0); break;
                case g: h = (b - r) / d + 2; break;
                case b: h = (r - g) / d + 4; break;
            }
            h /= 6;
        }
    
        return [h, s, l];
    }
    
    /**
     * Converts an HSL color value to RGB. Conversion formula
     * adapted from http://en.wikipedia.org/wiki/HSL_color_space.
     * Assumes h, s, and l are contained in the set [0, 1] and
     * returns r, g, and b in the set [0, 255].
     *
     * @param   Number  h       The hue
     * @param   Number  s       The saturation
     * @param   Number  l       The lightness
     * @return  Array           The RGB representation
     */
    function hslToRgb(h, s, l){
        var r, g, b;
    
        if(s == 0){
            r = g = b = l; // achromatic
        }else{
            function hue2rgb(p, q, t){
                if(t < 0) t += 1;
                if(t > 1) t -= 1;
                if(t < 1/6) return p + (q - p) * 6 * t;
                if(t < 1/2) return q;
                if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
                return p;
            }
    
            var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
            var p = 2 * l - q;
            r = hue2rgb(p, q, h + 1/3);
            g = hue2rgb(p, q, h);
            b = hue2rgb(p, q, h - 1/3);
        }
    
        return [r * 255, g * 255, b * 255];
    }
    

    我用它做了一些例子。检查此链接:http://jsfiddle.net/sangdol/euSLy/4/

    这是increase_brightness()函数:

    function increase_brightness(rgbcode, percent) {
        var r = parseInt(rgbcode.slice(1, 3), 16),
            g = parseInt(rgbcode.slice(3, 5), 16),
            b = parseInt(rgbcode.slice(5, 7), 16),
            HSL = rgbToHsl(r, g, b),
            newBrightness = HSL[2] + HSL[2] * (percent / 100), 
            RGB;
    
        RGB = hslToRgb(HSL[0], HSL[1], newBrightness);
        rgbcode = '#'
            + convertToTwoDigitHexCodeFromDecimal(RGB[0])
            + convertToTwoDigitHexCodeFromDecimal(RGB[1])
            + convertToTwoDigitHexCodeFromDecimal(RGB[2]);
    
        return rgbcode;
    }
    
    function convertToTwoDigitHexCodeFromDecimal(decimal){
        var code = Math.round(decimal).toString(16);
    
        (code.length > 1) || (code = '0' + code);
        return code;
    }
    

    您可以将负值作为percent 参数传递以使其变暗。

    【讨论】:

    • 不错的解决方案,但过于复杂。您可以在 RGB 中完成所有操作,而无需来回翻转。
    • @cwolves 是的,这很复杂。但是,此解决方案设置了颜色的真实亮度。我认为您的解决方案很简单,但它只是计算 RGB 代码的数量,我不认为该数字与亮度的增加比例相同。
    • @Sangdol - 如果您查看它生成的数字,它实际上是相同的。例外情况是,您还可以通过控制 0-100 值的饱和度来内置“变暗”功能。基本上,您的“51-100”是一种“减轻”,其功能与我的代码相同。如果你在我的代码中翻转几个数字,你会得到一个变暗的数字,那就是你的“0-49”
    • @Sangdol - 将其变暗,您只需将r + (256 - r) * percent / 100 替换为r * (100 - percent) / 100。正如我所说,您的解决方案没有任何问题,但是进行 RGB->HSL->RGB 转换只是一种浪费。简单地说,亮度就是颜色与白色或黑色的接近程度。因此,要使某些东西更亮 50%,您只需将颜色和白色之间的差异分开即可。相当简单的逻辑:)
    • 我尝试了多个问题的多个答案,但这是我真正想要的。这些答案的作用是,无论颜色是浅色还是深色,它们都会将颜色减少一定的百分比/量,从而使较浅的颜色透明,但是这个答案将每种颜色更改为固定的相同百分比,例如。亮度提高 95%。
    【解决方案5】:

    这里是RGB->HSL->RGB方法的increasBrightness函数。 “金额”应该是百分比。

    HSL取自http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript的RGB转换函数

    function increaseBrightness( color, amount ) {
        var r = parseInt(color.substr(1, 2), 16);
        var g = parseInt(color.substr(3, 2), 16);
        var b = parseInt(color.substr(5, 2), 16);
        hsl = rgbToHsl( r, g, b );
        hsl.l += hsl.l + (amount / 100);
        if( hsl.l > 1 ) hsl.l = 1;
        rgb = hslToRgb( hsl.h, hsl.s, hsl.l );
    
        var v = rgb.b | (rgb.g << 8) | (rgb.r << 16);
        return '#' + v.toString(16);
    }
    
    function rgbToHsl(r, g, b){
        r /= 255, g /= 255, b /= 255;
        var max = Math.max(r, g, b), min = Math.min(r, g, b);
        var h, s, l = (max + min) / 2;
    
        if(max == min){
            h = s = 0; // achromatic
        }else{
            var d = max - min;
            s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
            switch(max){
                case r: h = (g - b) / d + (g < b ? 6 : 0); break;
                case g: h = (b - r) / d + 2; break;
                case b: h = (r - g) / d + 4; break;
            }
            h /= 6;
        }
        return {'h':h, 's':s, 'l':l};
    }
    
    function hslToRgb(h, s, l){
        var r, g, b;
    
        if(s == 0){
            r = g = b = l; // achromatic
        }else{
            function hue2rgb(p, q, t){
                if(t < 0) t += 1;
                if(t > 1) t -= 1;
                if(t < 1/6) return p + (q - p) * 6 * t;
                if(t < 1/2) return q;
                if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
                return p;
            }
    
            var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
            var p = 2 * l - q;
            r = hue2rgb(p, q, h + 1/3);
            g = hue2rgb(p, q, h);
            b = hue2rgb(p, q, h - 1/3);
        }
    
        return { 'r':r * 255, 'g':g * 255, 'b':b * 255 };
    }
    

    【讨论】:

    • 感谢您的意见!如果需要以百分比表示,为什么不将amount 重命名为percent?或者像亮度百分比?
    【解决方案6】:

    如果有人需要,我将颜色亮度 JavaScript 代码转换为 ASP / VBScript 用于一个项目,并认为我会与您分享:

    '::Color Brightness (0-100)
    'ex.     ColorBrightness("#FF0000",25)  'Darker
    'ex.     ColorBrightness("#FF0000",50)  'Mid
    'ex.     ColorBrightness("#FF0000",75)  'Lighter
    Function ColorBrightness(strRGB,intBrite)
        strRGB = Replace(strRGB,"#","")
    
        r = CInt("&h" & Mid(strRGB,1,2))
        g = CInt("&h" & Mid(strRGB,3,2))
        b = CInt("&h" & Mid(strRGB,5,2))
    
        arrHSL = RGBtoHSL(r, g, b)
        dblOrigBrite = CDbl(arrHSL(2) * 100)
    
        arrRGB = HSLtoRGB(arrHSL(0), arrHSL(1), intBrite/100)
        newRGB = "#" & HEXtoDEC(arrRGB(0)) & HEXtoDEC(arrRGB(1)) & HEXtoDEC(arrRGB(2))
    
        ColorBrightness = newRGB
    End Function
    
    
    '::RGB to HSL Function
    Function RGBtoHSL(r,g,b)
        r = CDbl(r/255)
        g = CDbl(g/255)
        b = CDbl(b/255)
    
        max = CDbl(MaxCalc(r & "," & g & "," & b))
        min = CDbl(MinCalc(r & "," & g & "," & b))
    
        h = CDbl((max + min) / 2)
        s = CDbl((max + min) / 2)
        l = CDbl((max + min) / 2)
    
        If max = min Then
            h = 0
            s = 0
        Else
            d = max - min
            s = IIf(l > 0.5, d / (2 - max - min), d / (max + min))
            Select Case CStr(max)
                Case CStr(r)
                    h = (g - b) / d + (IIf(g < b, 6, 0))
                Case CStr(g)
                    h = (b - r) / d + 2
                Case CStr(b)
                    h = (r - g) / d + 4
            End Select
            h = h / 6
        End If
    
        RGBtoHSL = Split(h & "," & s & "," & l, ",")
    End Function
    
    
    '::HSL to RGB Function
    Function HSLtoRGB(h,s,l)
        If s = 0 Then
            r = l
            g = l
            b = l
        Else
            q = IIf(l < 0.5, l * (1 + s), l + s - l * s)
            p = 2 * l - q
            r = HUEtoRGB(p, q, h + 1/3)
            g = HUEtoRGB(p, q, h)
            b = HUEtoRGB(p, q, h - 1/3)
        End If
    
        HSLtoRGB = Split(r * 255 & "," & g * 255 & "," & b * 255, ",")
    End Function
    
    
    '::Hue to RGB Function
    Function HUEtoRGB(p,q,t)
        If CDbl(t) < 0 Then t = t + 1
        If CDbl(t) > 1 Then t = t - 1
    
        If CDbl(t) < (1/6) Then
            HUEtoRGB = p + (q - p) * 6 * t
            Exit Function
        End If
    
        If CDbl(t) < (1/2) Then
            HUEtoRGB = q
            Exit Function
        End If
    
        If CDbl(t) < (2/3) Then
            HUEtoRGB = p + (q - p) * (2/3 - t) * 6
            Exit Function
        End If
    
        HUEtoRGB = p
    End Function
    
    
    '::Hex to Decimal Function
    Function HEXtoDEC(d)
        h = Hex(Round(d,0))
        h = Right(String(2,"0") & h,2)
        HEXtoDEC = h
    End Function
    
    
    '::Max Function
    Function MaxCalc(valList)
        valList = Split(valList,",")
        b = 0
        For v = 0 To UBound(valList)
            a = valList(v)
            If CDbl(a) > CDbl(b) Then b = a
        Next
        MaxCalc = b
    End Function
    
    
    '::Min Function
    Function MinCalc(valList)
        valList = Split(valList,",")
        For v = 0 To UBound(valList)
            a = valList(v)
            If b = "" Then b = a
            If CDbl(a) < CDbl(b) AND b <> "" Then b = a
        Next
        MinCalc = b
    End Function
    
    
    '::IIf Emulation Function
    Function IIf(condition,conTrue,conFalse)
        If (condition) Then
            IIf = conTrue
        Else
            IIf = conFalse
        End If
    End Function
    

    【讨论】:

      【解决方案7】:

      这样您就不需要对源颜色进行任何转换。
      看看这个小提琴:https://jsfiddle.net/4c47otou/

      increase_brightness = function(color,percent){
      
          var ctx = document.createElement('canvas').getContext('2d');
      
          ctx.fillStyle = color;
          ctx.fillRect(0,0,1,1);
      
          var color = ctx.getImageData(0,0,1,1);
          var r = color.data[0] + Math.floor( percent / 100 * 255 );
          var g = color.data[1] + Math.floor( percent / 100 * 255 );
          var b = color.data[2] + Math.floor( percent / 100 * 255 );
      
          return 'rgb('+r+','+g+','+b+')';
      }
      

      示例用法:

      increase_brightness('#0000ff',20);
      increase_brightness('khaki',20);
      increase_brightness('rgb(12, 7, 54)',20);
      

      【讨论】:

        【解决方案8】:

        我发现 Sanghyun Lee 的回复的变体产生了最好的结果。

        1. 将 RGB 转换为 HSL
        2. 设置 HSL 的亮度
        3. 从 HSL 转换回 RGB

        差异/变化是您增加/减少亮度的方式。

        newBrightness = HSL[2] + HSL[2] * (percent / 100) // Original code
        

        与其对当前亮度应用百分比,不如将其视为绝对增量/减量。由于亮度范围是 0 到 1,因此百分比可以应用于整个范围 (1 - 0) * percent/100。

        newBrightness = HSL[2] + (percent / 100);
        newBrightness = Math.max(0, Math.min(1, newBrightness));
        

        这种方法的另一个很好的特性是递增和递减相互否定。

        下图显示了以 5% 为增量的较深和较浅的颜色。请注意,调色板是如何相当平滑且通常以黑白结尾的。

        采用原始方法的调色板 - 卡在某些颜色上。

        【讨论】:

          【解决方案9】:

          带有lodash的变体:

          // color('#EBEDF0', 30)
          color(hex, percent) {
            return '#' + _(hex.replace('#', '')).chunk(2)
              .map(v => parseInt(v.join(''), 16))
              .map(v => ((0 | (1 << 8) + v + (256 - v) * percent / 100).toString(16))
              .substr(1)).join('');
          }
          

          【讨论】:

            【解决方案10】:

            我知道这是一个老问题,但我没有找到简单地操纵 css hsl 颜色的答案。我发现这里的旧答案过于复杂和缓慢,甚至会产生糟糕的结果,因此似乎需要采用不同的方法。以下替代方案性能更高,复杂性更低。

            当然,这个答案要求你在整个应用程序中使用 hsl 颜色,否则你仍然需要进行一堆转换!但是,如果您需要在游戏循环中操作亮度,则无论如何都应该使用 hsl 值,因为它们更适合编程操作。据我所知,hsl from rgb 的唯一缺点是,很难像使用 rgb 字符串那样“读取”您看到的色调。

            function toHslArray(hslCss) {
                let sep = hslCss.indexOf(",") > -1 ? "," : " "
                return hslCss.substr(4).split(")")[0].split(sep)
            }
            
            function adjustHslBrightness(color, percent) {
                let hsl = toHslArray(color)
                return "hsl(" + hsl[0] + "," + hsl[1] + ", " + (percent + "%") + ")"
            }
            
            let hsl = "hsl(200, 40%, 40%)"
            let hsl2 = adjustHslBrightness(hsl, 80)
            

            【讨论】:

              【解决方案11】:

              我用什么:

              //hex can be string or number
              //rate: 1 keeps the color same. < 1 darken. > 1 lighten.
              //to_string: set to true if you want the return value in string
              function change_brightness(hex, rate, to_string = false) {
                  if (typeof hex === 'string') {
                      hex = hex.replace(/^\s*#|\s*$/g, '');
                  } else {
                      hex = hex.toString(16);
                  }
                  if (hex.length == 3) {
                      hex = hex.replace(/(.)/g, '$1$1');
                  } else {
                      hex = ("000000" + hex).slice(-6);
                  }
                  let r = parseInt(hex.substr(0, 2), 16);
                  let g = parseInt(hex.substr(2, 2), 16);
                  let b = parseInt(hex.substr(4, 2), 16);
              
                  let h, s, v;
                  [h, s, v] = rgb2hsv(r, g, b);
                  v = parseInt(v * rate);
                  [r, g, b] = hsv2rgb(h, s, v);
              
                  hex = ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
                  if (to_string) return "#" + hex;
                  return parseInt(hex, 16);
              }
              
              function rgb2hsv(r,g,b) {
                  let v = Math.max(r,g,b), n = v-Math.min(r,g,b);
                  let h = n && ((v === r) ? (g-b)/n : ((v === g) ? 2+(b-r)/n : 4+(r-g)/n)); 
                  return [60*(h<0?h+6:h), v&&n/v, v];
              }
              
              function hsv2rgb(h,s,v) {
                  let f = (n,k=(n+h/60)%6) => v - v*s*Math.max( Math.min(k,4-k,1), 0);
                  return [f(5),f(3),f(1)];
              }
              

              【讨论】:

                【解决方案12】:

                function brighten(color, c) {
                  const calc = (sub1,sub2)=> Math.min(255,Math.floor(parseInt(color.substr(sub1,sub2),16)*c)).toString(16).padStart(2,"0")
                  return `#${calc(1,2)}${calc(3,2)}${calc(5,2)}`
                }
                
                const res = brighten("#23DA4C", .5) // "#116d26"
                console.log(res)

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2012-11-02
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2012-07-07
                  • 2017-04-03
                  • 2015-07-21
                  相关资源
                  最近更新 更多