微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

以编程方式使十六进制颜色变亮或变暗或 rgb 和混合颜色

如何解决以编程方式使十六进制颜色变亮或变暗或 rgb 和混合颜色

好吧,这个答案已经成为它自己的野兽。 许多新版本,它变得越来越愚蠢。非常感谢所有对此答案的众多贡献者。但是,为了让大众保持简单。我将此答案演变的所有版本/历史存档到我的github。并在 StackOverflow 上使用最新版本重新开始。特别感谢Mike ‘Pomax’ Kamermans的这个版本。他给了我新的数学。


函数 ( pSBC) 将采用 HEX 或 RGB 网络颜色。pSBC可以将其着色得更深或更浅,或者将其与第二种颜色混合,也可以将其直接传递,但将其从十六进制转换为 RGB (Hex2RGB) 或将 RGB 转换为十六进制 (RGB2Hex)。您甚至都不知道您使用的是什么颜色格式。

这运行得非常快,可能是最快的,尤其是考虑到它的许多特性。这是一个很长的时间。在我的github上查看整个故事。如果您想要绝对最小和最快的着色或混合方式,请参阅下面的微功能并使用 2 线速度恶魔之一。它们非常适合激烈的动画,但这里的这个版本对于大多数动画来说已经足够快了。

功能使用对数混合或线性混合。但是,它不会转换为 HSL 以适当地使颜色变亮或变暗。因此, 使用 HSL 的那些更大且更慢的函数

jsFiddle 与 pSBC

github > pSBC 维基

特征:

  • 自动检测并接受字符串形式的标准十六进制颜色。例如:"#AA6622""#bb551144"
  • 自动检测并接受字符串形式的标准 RGB 颜色。例如:"rgb(123,45,76)""rgba(45,15,74,0.45)"
  • 按百分比将颜色渐变为白色或黑色。
  • 按百分比将颜色混合在一起。
  • 同时进行 Hex2RGB 和 RGB2Hex 转换,或者单独进行。
  • 接受 3 位(或 4 位带 alpha 的)十六进制颜色代码,格式为 #RGB(或 #RGBA)。它将扩展它们。例如:"#C41"变成"#CC4411".
  • 接受并(线性)混合 Alpha 通道。如果c0(from) 颜色或c1(to) 颜色具有 alpha 通道,则返回的颜色将具有 alpha 通道。如果两种颜色都有一个 alpha 通道,则返回的颜色将是使用给定百分比的两个 alpha 通道的线性混合(就像它是一个正常的颜色通道一样)。如果两种颜色中只有一种具有 alpha 通道,则此 alpha 将直接传递给返回的颜色。这允许在保持透明度级别的同时混合/着色透明颜色。或者,如果透明度级别也应该混合,请确保两种颜色都有 alpha。着色时,它将直接通过 Alpha 通道。如果您想要同时对 Alpha 通道进行着色的基本着色,请使用rgb(0,0,0,1)rgb(255,255,255,1)作为您的c1(到)颜色(或它们的十六进制等价物)。对于 RGB 颜色,返回颜色的 alpha 通道将四舍五入到小数点后 3 位。
  • 使用混合时,RGB2Hex 和 Hex2RGB 转换是隐式的。无论c0(从)颜色如何;如果存在,返回的颜色将始终采用c1(to) 颜色的颜色格式。如果没有(到)颜色,则作为颜色c1传入,它将着色并转换任何颜色。如果只需要转换,则也以百分比 ( ) 的形式传入。如果省略颜色或传入非-,则不会转换。'c'``c1``c0``0``p``c1``string
  • 辅助函数也被添加到全局中。pSBCr可以传递一个 Hex 或 RGB 颜色,它返回一个包含此颜色信息的对象。格式为:{r: XXX, g: XXX, b: XXX, a: X.XXX}。其中.r.g.b的范围为 0 到 255。当没有 alpha 时:.a为 -1。否则:.a范围为 0.000 到 1.000。
  • 对于 RGB 输出rgba()rgb()带有 alpha 通道的颜色被传递到c0(from) 和/或c1(to) 时,它会输出
  • 添加了小错误检​​查。这并不完美。它仍然可能崩溃或产生乱码。但它会抓住一些东西。基本上,如果结构在某些方面是错误的,或者百分比不是数字或超出范围,它将返回null. 一个例子:pSBC(0.5,"salt") == null,它认为#salt是有效的颜色。删除以结尾的四行return null;删除功能并使其更快更小。
  • 使用对数混合。传入truefor l(第 4 个参数)以使用线性混合。

代码

// Version 4.0
const pSBC=(p,c0,c1,l)=>{
    let r,g,b,P,f,t,h,i=parseInt,m=Math.round,a=typeof(c1)=="string";
    if(typeof(p)!="number"||p<-1||p>1||typeof(c0)!="string"||(c0[0]!='r'&&c0[0]!='#')||(c1&&!a))return null;
    if(!this.pSBCr)this.pSBCr=(d)=>{
        let n=d.length,x={};
        if(n>9){
            [r,g,b,a]=d=d.split(","),n=d.length;
            if(n<3||n>4)return null;
            x.r=i(r[3]=="a"?r.slice(5):r.slice(4)),x.g=i(g),x.b=i(b),x.a=a?parseFloat(a):-1
        }else{
            if(n==8||n==6||n<4)return null;
            if(n<6)d="#"+d[1]+d[1]+d[2]+d[2]+d[3]+d[3]+(n>4?d[4]+d[4]:"");
            d=i(d.slice(1),16);
            if(n==9||n==5)x.r=d>>24&255,x.g=d>>16&255,x.b=d>>8&255,x.a=m((d&255)/0.255)/1000;
            else x.r=d>>16,x.g=d>>8&255,x.b=d&255,x.a=-1
        }return x};
    h=c0.length>9,h=a?c1.length>9?true:c1=="c"?!h:false:h,f=this.pSBCr(c0),P=p<0,t=c1&&c1!="c"?this.pSBCr(c1):P?{r:0,g:0,b:0,a:-1}:{r:255,g:255,b:255,a:-1},p=P?P*-1:p,P=1-p;
    if(!f||!t)return null;
    if(l)r=m(P*f.r+P*t.r),g=m(P*f.g+P*t.g),b=m(P*f.b+P*t.b);
    else r=m((P*f.r**2+P*t.r**2)**0.5),g=m((P*f.g**2+P*t.g**2)**0.5),b=m((P*f.b**2+P*t.b**2)**0.5);
    a=f.a,t=t.a,f=a>=0||t>=0,a=f?a<0?t:t<0?a:a*P+t*p:0;
    if(h)return"rgb"+(f?"a(":"(")+r+","+g+","+b+(f?","+m(a*1000)/1000:"")+")";
    else return"#"+(4294967296+r*16777216+g*65536+b*256+(f?m(a*255):0)).toString(16).slice(1,f?undefined:-2)
}

用法

// Setup:

let color1 = "rgb(20,60,200)";
let color2 = "rgba(20,60,200,0.67423)";
let color3 = "#67DAF0";
let color4 = "#5567DAF0";
let color5 = "#F3A";
let color6 = "#F3A9";
let color7 = "rgb(200,60,20)";
let color8 = "rgba(200,60,20,0.98631)";

// Tests:

/*** Log Blending ***/
// Shade (Lighten or Darken)
pSBC ( 0.42, color1 ); // rgb(20,60,200) + [42% Lighter] => rgb(166,171,225)
pSBC ( -0.4, color5 ); // #F3A + [40% Darker] => #c62884
pSBC ( 0.42, color8 ); // rgba(200,60,20,0.98631) + [42% Lighter] => rgba(225,171,166,0.98631)

// Shade with Conversion (use "c" as your "to" color)
pSBC ( 0.42, color2, "c" ); // rgba(20,60,200,0.67423) + [42% Lighter] + [Convert] => #a6abe1ac

// RGB2Hex & Hex2RGB Conversion Only (set percentage to zero)
pSBC ( 0, color6, "c" ); // #F3A9 + [Convert] => rgba(255,51,170,0.6)

// Blending
pSBC ( -0.5, color2, color8 ); // rgba(20,60,200,0.67423) + rgba(200,60,20,0.98631) + [50% Blend] => rgba(142,60,142,0.83)
pSBC ( 0.7, color2, color7 ); // rgba(20,60,200,0.67423) + rgb(200,60,20) + [70% Blend] => rgba(168,60,111,0.67423)
pSBC ( 0.25, color3, color7 ); // #67DAF0 + rgb(200,60,20) + [25% Blend] => rgb(134,191,208)
pSBC ( 0.75, color7, color3 ); // rgb(200,60,20) + #67DAF0 + [75% Blend] => #86bfd0

/*** Linear Blending ***/
// Shade (Lighten or Darken)
pSBC ( 0.42, color1, false, true ); // rgb(20,60,200) + [42% Lighter] => rgb(119,142,223)
pSBC ( -0.4, color5, false, true ); // #F3A + [40% Darker] => #991f66
pSBC ( 0.42, color8, false, true ); // rgba(200,60,20,0.98631) + [42% Lighter] => rgba(223,142,119,0.98631)

// Shade with Conversion (use "c" as your "to" color)
pSBC ( 0.42, color2, "c", true ); // rgba(20,60,200,0.67423) + [42% Lighter] + [Convert] => #778edfac

// RGB2Hex & Hex2RGB Conversion Only (set percentage to zero)
pSBC ( 0, color6, "c", true ); // #F3A9 + [Convert] => rgba(255,51,170,0.6)

// Blending
pSBC ( -0.5, color2, color8, true ); // rgba(20,60,200,0.67423) + rgba(200,60,20,0.98631) + [50% Blend] => rgba(110,60,110,0.83)
pSBC ( 0.7, color2, color7, true ); // rgba(20,60,200,0.67423) + rgb(200,60,20) + [70% Blend] => rgba(146,60,74,0.67423)
pSBC ( 0.25, color3, color7, true ); // #67DAF0 + rgb(200,60,20) + [25% Blend] => rgb(127,179,185)
pSBC ( 0.75, color7, color3, true ); // rgb(200,60,20) + #67DAF0 + [75% Blend] => #7fb3b9

/*** Other Stuff ***/
// Error Checking
pSBC ( 0.42, "#FFBAA" ); // #FFBAA + [42% Lighter] =>

解决方法

这是我正在研究的一个函数,它可以通过编程方式将十六进制颜色变亮或变暗特定量。只需传入一个字符串,比如"3F6D2A"颜色 ( col) 和一个
base10 整数 ( amt) 来表示变亮或变暗的量。要变暗,请传入一个负数(即-20)。

我这样做的原因是因为我找到的所有解决方案,到目前为止,它们似乎使问题过于复杂。我有一种感觉,只需几行代码就可以完成。如果您发现任何问题或进行任何调整以加快速度,请告诉我。

function LightenDarkenColor(col,amt) {

  col = parseInt(col,16);

  return (((col & 0x0000FF) + amt) | ((((col >> 8) & 0x00FF) + amt) << 8) | (((col >> 16) + amt) << 16)).toString(16);

}





// TEST

console.log( LightenDarkenColor("3F6D2A",40) );

对于开发使用,这里是一个更易于阅读的版本:

function LightenDarkenColor(col,amt) {

  var num = parseInt(col,16);

  var r = (num >> 16) + amt;

  var b = ((num >> 8) & 0x00FF) + amt;

  var g = (num & 0x0000FF) + amt;

  var newColor = g | (b << 8) | (r << 16);

  return newColor.toString(16);

}





// TEST

console.log(LightenDarkenColor("3F6D2A",-40));

最后一个版本可以处理开头可能(或可能没有)带有“#”的颜色。加上调整不正确的颜色值:

function LightenDarkenColor(col,amt) {
    var usePound = false;
    if ( col[0] == "#" ) {
        col = col.slice(1);
        usePound = true;
    }

    var num = parseInt(col,16);

    var r = (num >> 16) + amt;

    if ( r > 255 ) r = 255;
    else if  (r < 0) r = 0;

    var b = ((num >> 8) & 0x00FF) + amt;

    if ( b > 255 ) b = 255;
    else if  (b < 0) b = 0;

    var g = (num & 0x0000FF) + amt;

    if ( g > 255 ) g = 255;
    else if  ( g < 0 ) g = 0;

    return (usePound?"#":"") + (g | (b << 8) | (r << 16)).toString(16);
}

好的,所以现在它不仅仅是几行,但它似乎更简单,如果你不使用“#”并且不需要检查超出范围的颜色,它只有几行。

如果不使用“#”,您可以将其添加到如下代码中:

var myColor = "3F6D2A";
myColor = LightenDarkenColor(myColor,10);
thePlaceTheColorIsUsed = ("#" + myColor);

我想我的主要问题是,我在这里正确吗?这不包括一些(正常)情况吗?

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。