Javascript 以编程方式使十六进制颜色(或 rgb 和混合颜色)变亮或变暗
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5560248/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Programmatically Lighten or Darken a hex color (or rgb, and blend colors)
提问by Pimp Trizkit
Here is a function I was working on to programmatically lighten or darken a hex color by a specific amount. Just pass in a string like "3F6D2A"
for the color (col
) and a base10 integer (amt
) for the amount to lighten or darken. To darken, pass in a negative number (i.e. -20
).
这是我正在使用的一个函数,以编程方式使十六进制颜色变亮或变暗特定数量。只需传入一个类似"3F6D2A"
颜色的字符串( col
) 和一个 base10 整数 ( amt
) 来表示变亮或变暗的数量。要变暗,请传入一个负数(即-20
)。
The reason for me to do this was because of all the solutions I found, thus far, they seemed to over-complicate the issue. And I had a feeling it could be done with just a couple lines of code. Please let me know if you find any problems, or have any adjustments to make that would speed it up.
我这样做的原因是因为我找到的所有解决方案,到目前为止,它们似乎使问题过于复杂。我有一种感觉,只需几行代码就可以完成。如果您发现任何问题,或者有任何调整可以加快速度,请告诉我。
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) );
For Development use here is an easier to read version:
对于开发使用,这里是一个更容易阅读的版本:
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));
And finally a version to handle colors that may (or may not) have the "#" in the beginning. Plus adjusting for improper color values:
最后一个版本可以处理开头可能(也可能没有)带有“#”的颜色。加上调整不正确的颜色值:
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);
}
OK, so now it's not just a couple of lines, but it seems far simpler and if you're not using the "#" and don't need to check for colors out of range, it is only a couple of lines.
好的,所以现在它不仅仅是几行,但它看起来要简单得多,如果您不使用“#”并且不需要检查超出范围的颜色,那么它只是几行。
If not using the "#", you can just add it in code like:
如果不使用“#”,您可以将其添加到代码中,例如:
var myColor = "3F6D2A";
myColor = LightenDarkenColor(myColor,10);
thePlaceTheColorIsUsed = ("#" + myColor);
I guess my main question is, am I correct here? Does this not encompass some (normal) situations?
我想我的主要问题是,我在这里正确吗?这不包括某些(正常)情况吗?
回答by Pimp Trizkit
Well, this answer has become its own beast. Many new versions, it was getting stupid long. Many thanks to all of the great many contributors to this answer. But, in order to keep it simple for the masses. I archived all the versions/history of this answer's evolution to my github. And started it over clean on StackOverflow here with the newest version. A special thanks goes out to Mike 'Pomax' Kamermansfor this version. He gave me the new math.
好吧,这个答案已经成为它自己的野兽。许多新版本,它变得愚蠢了很久。非常感谢这个答案的所有贡献者。但是,为了让大众保持简单。我将这个答案演变的所有版本/历史存档到我的github。并使用最新版本在 StackOverflow 上重新开始。特别感谢Mike 'Pomax' Kamermans 制作了这个版本。他给了我新的数学。
This function (pSBC
) will take a HEX or RGB web color. pSBC
can shade it darker or lighter, or blend it with a second color, and can also pass it right thru but convert from Hex to RGB (Hex2RGB) or RGB to Hex (RGB2Hex). All without you even knowing what color format you are using.
此函数 ( pSBC
) 将采用 HEX 或 RGB 网络颜色。pSBC
可以将其着色为更暗或更亮,或将其与第二种颜色混合,也可以将其直接传递但将其从十六进制转换为 RGB (Hex2RGB) 或从 RGB 转换为十六进制 (RGB2Hex)。您甚至都不知道您使用的是什么颜色格式。
This runs really fast, probably the fastest, especially considering its many features. It was a long time in the making. See the whole story on my github. If you want the absolutely smallest and fastest possible way to shade or blend, see the Micro Functions below and use one of the 2-liner speed demons. They are great for intense animations, but this version here is fast enough for most animations.
这运行得非常快,可能是最快的,尤其是考虑到它的许多功能。酝酿已久。在我的github上查看整个故事。如果您想要绝对最小和最快的着色或混合方式,请参阅下面的微功能并使用 2 线速度恶魔之一。它们非常适合激烈的动画,但这里的这个版本对于大多数动画来说已经足够快了。
This function uses Log Blending or Linear Blending. However, it does NOT convert to HSL to properly lighten or darken a color. Therefore, results from this function will differfrom those much larger and much slower functions that use HSL.
此功能使用对数混合或线性混合。但是,它不会转换为 HSL 以适当地使颜色变亮或变暗。因此,此函数的结果将不同于使用 HSL 的那些更大、更慢的函数。
Features:
特征:
- Auto-detects and accepts standard Hex colors in the form of strings. For example:
"#AA6622"
or"#bb551144"
. - Auto-detects and accepts standard RGB colors in the form of strings. For example:
"rgb(123,45,76)"
or"rgba(45,15,74,0.45)"
. - Shades colors to white or black by percentage.
- Blends colors together by percentage.
- Does Hex2RGB and RGB2Hex conversion at the same time, or solo.
- Accepts 3 digit (or 4 digit w/ alpha) HEX color codes, in the form #RGB (or #RGBA). It will expand them. For Example:
"#C41"
becomes"#CC4411"
. - Accepts and (Linear) blends alpha channels. If either the
c0
(from) color or thec1
(to) color has an alpha channel, then the returned color will have an alpha channel. If both colors have an alpha channel, then the returned color will be a linear blend of the two alpha channels using the percentage given (just as if it were a normal color channel). If only one of the two colors has an alpha channel, this alpha will just be passed thru to the returned color. This allows one to blend/shade a transparent color while maintaining the transparency level. Or, if the transparency levels should blend as well, make sure both colors have alphas. When shading, it will pass the alpha channel straight thru. If you want basic shading that also shades the alpha channel, then usergb(0,0,0,1)
orrgb(255,255,255,1)
as yourc1
(to) color (or their hex equivalents). For RGB colors, the returned color's alpha channel will be rounded to 3 decimal places. - RGB2Hex and Hex2RGB conversions are implicit when using blending. Regardless of the
c0
(from) color; the returned color will always be in the color format of thec1
(to) color, if one exists. If there is noc1
(to) color, then pass'c'
in as thec1
color and it will shade and convert whatever thec0
color is. If conversion only is desired, then pass0
in as the percentage (p
) as well. If thec1
color is omitted or a non-string
is passed in, it will not convert. - A secondary function is added to the global as well.
pSBCr
can be passed a Hex or RGB color and it returns an object containing this color information. Its in the form: {r: XXX, g: XXX, b: XXX, a: X.XXX}. Where.r
,.g
, and.b
have range 0 to 255. And when there is no alpha:.a
is -1. Otherwise:.a
has range 0.000 to 1.000. - For RGB output, it outputs
rgba()
overrgb()
when a color with an alpha channel was passed intoc0
(from) and/orc1
(to). - Minor Error Checking has been added. It's not perfect. It can still crash or create jibberish. But it will catch some stuff. Basically, if the structure is wrong in some ways or if the percentage is not a number or out of scope, it will return
null
. An example:pSBC(0.5,"salt") == null
, where as it thinks#salt
is a valid color. Delete the four lines which end withreturn null;
to remove this feature and make it faster and smaller. - Uses Log Blending. Pass
true
in forl
(the 4th parameter) to use Linear Blending.
- 自动检测并接受字符串形式的标准十六进制颜色。例如:
"#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 将直接传递给返回的颜色。这允许在保持透明度级别的同时混合/着色透明颜色。或者,如果透明度级别也应该混合,请确保两种颜色都有 alphas。着色时,它将直接通过 alpha 通道。如果你想要基本的着色同时也对 alpha 通道进行着色,那么使用rgb(0,0,0,1)
或rgb(255,255,255,1)
作为你的c1
(到)颜色(或它们的十六进制等价物)。对于 RGB 颜色,返回颜色的 alpha 通道将四舍五入到小数点后 3 位。 - 使用混合时,RGB2Hex 和 Hex2RGB 转换是隐式的。不管
c0
(从)颜色;返回的颜色将始终采用c1
(到)颜色的颜色格式(如果存在)。如果没有c1
(to) 颜色,则'c'
作为c1
颜色传入,它将着色并转换任何c0
颜色。如果只需要转换,则0
也以百分比 (p
) 的形式传入。如果c1
省略颜色或string
传入非,则不会转换。 - 辅助功能也被添加到全局中。
pSBCr
可以传递十六进制或 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;
以删除此功能并使其更快更小。 - 使用日志混合。传入
true
forl
(第四个参数)以使用线性混合。
Code:
代码:
// 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)
}
Usage:
用法:
// 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] => null??(Invalid Input Color)
pSBC ( 42, color1, color5 ); // rgb(20,60,200) + #F3A + [4200% Blend] => null??(Invalid Percentage Range)
pSBC ( 0.42, {} ); // [object Object] + [42% Lighter] => null??(Strings Only for Color)
pSBC ( "42", color1 ); // rgb(20,60,200) + ["42"] => null??(Numbers Only for Percentage)
pSBC ( 0.42, "salt" ); // salt + [42% Lighter] => null??(A Little Salt is No Good...)
// Error Check Fails?(Some Errors are not Caught)
pSBC ( 0.42, "#salt" ); // #salt + [42% Lighter] => #a5a5a500??(...and a Pound of Salt is Jibberish)
// Ripping
pSBCr ( color4 ); // #5567DAF0 + [Rip] => [object Object] => {'r':85,'g':103,'b':218,'a':0.941}
The picture below will help show the difference in the two blending methods:
下图将有助于显示两种混合方法的差异:
Micro Functions
微功能
If you really want speed and size, you will have to use RGB not HEX. RGB is more straightforward and simple, HEX writes too slow and comes in too many flavors for a simple two-liner (IE. it could be a 3, 4, 6, or 8 digit HEX code). You will also need to sacrifice some features, no error checking, no HEX2RGB nor RGB2HEX. As well, you will need to choose a specific function (based on its function name below) for the color blending math, and if you want shading or blending. These functions do support alpha channels. And when both input colors have alphas it will Linear Blend them. If only one of the two colors has an alpha, it will pass it straight thru to the resulting color. Below are two liner functions that are incredibly fast and small:
如果你真的想要速度和大小,你将不得不使用 RGB 而不是 HEX。RGB 更直接和简单,HEX 写得太慢,而且对于简单的两行代码(即,它可能是 3、4、6 或 8 位十六进制代码)有太多的风格。您还需要牺牲一些功能,没有错误检查,没有 HEX2RGB 或 RGB2HEX。同样,您还需要为颜色混合数学选择一个特定的函数(根据下面的函数名称),以及是否需要着色或混合。这些函数确实支持 alpha 通道。当两种输入颜色都有 alpha 时,它将线性混合它们。如果两种颜色中只有一种具有 alpha,它将直接传递给生成的颜色。下面是两个非常快速和小巧的线性函数:
const RGB_Linear_Blend=(p,c0,c1)=>{
var i=parseInt,r=Math.round,P=1-p,[a,b,c,d]=c0.split(","),[e,f,g,h]=c1.split(","),x=d||h,j=x?","+(!d?h:!h?d:r((parseFloat(d)*P+parseFloat(h)*p)*1000)/1000+")"):")";
return"rgb"+(x?"a(":"(")+r(i(a[3]=="a"?a.slice(5):a.slice(4))*P+i(e[3]=="a"?e.slice(5):e.slice(4))*p)+","+r(i(b)*P+i(f)*p)+","+r(i(c)*P+i(g)*p)+j;
}
const RGB_Linear_Shade=(p,c)=>{
var i=parseInt,r=Math.round,[a,b,c,d]=c.split(","),P=p<0,t=P?0:255*p,P=P?1+p:1-p;
return"rgb"+(d?"a(":"(")+r(i(a[3]=="a"?a.slice(5):a.slice(4))*P+t)+","+r(i(b)*P+t)+","+r(i(c)*P+t)+(d?","+d:")");
}
const RGB_Log_Blend=(p,c0,c1)=>{
var i=parseInt,r=Math.round,P=1-p,[a,b,c,d]=c0.split(","),[e,f,g,h]=c1.split(","),x=d||h,j=x?","+(!d?h:!h?d:r((parseFloat(d)*P+parseFloat(h)*p)*1000)/1000+")"):")";
return"rgb"+(x?"a(":"(")+r((P*i(a[3]=="a"?a.slice(5):a.slice(4))**2+p*i(e[3]=="a"?e.slice(5):e.slice(4))**2)**0.5)+","+r((P*i(b)**2+p*i(f)**2)**0.5)+","+r((P*i(c)**2+p*i(g)**2)**0.5)+j;
}
const RGB_Log_Shade=(p,c)=>{
var i=parseInt,r=Math.round,[a,b,c,d]=c.split(","),P=p<0,t=P?0:p*255**2,P=P?1+p:1-p;
return"rgb"+(d?"a(":"(")+r((P*i(a[3]=="a"?a.slice(5):a.slice(4))**2+t)**0.5)+","+r((P*i(b)**2+t)**0.5)+","+r((P*i(c)**2+t)**0.5)+(d?","+d:")");
}
Want more info? Read the full writeup on github.
想了解更多信息?阅读github上的完整文章。
PT
PT
(P.s. If anyone has the math for another blending method, please share.)
(Ps 如果有人有另一种混合方法的数学方法,请分享。)
回答by Pablo
I made a solution that works very nice for me:
我做了一个对我来说非常有用的解决方案:
function shadeColor(color, percent) {
var R = parseInt(color.substring(1,3),16);
var G = parseInt(color.substring(3,5),16);
var B = parseInt(color.substring(5,7),16);
R = parseInt(R * (100 + percent) / 100);
G = parseInt(G * (100 + percent) / 100);
B = parseInt(B * (100 + percent) / 100);
R = (R<255)?R:255;
G = (G<255)?G:255;
B = (B<255)?B:255;
var RR = ((R.toString(16).length==1)?"0"+R.toString(16):R.toString(16));
var GG = ((G.toString(16).length==1)?"0"+G.toString(16):G.toString(16));
var BB = ((B.toString(16).length==1)?"0"+B.toString(16):B.toString(16));
return "#"+RR+GG+BB;
}
Example Lighten:
示例减轻:
shadeColor("#63C6FF",40);
Example Darken:
变暗示例:
shadeColor("#63C6FF",-40);
回答by supersan
Here is a super simple one liner based on Eric's answer
这是一个基于 Eric 的回答的超级简单的单线
function adjust(color, amount) {
return '#' + color.replace(/^#/, '').replace(/../g, color => ('0'+Math.min(255, Math.max(0, parseInt(color, 16) + amount)).toString(16)).substr(-2));
}
Examples:
例子:
adjust('#ffffff', -20) => "#ebebeb"
adjust('000000', 20) => "#141414"
回答by Eric Sloan
This is what I used based on your function. I prefer to use steps over percentage because it's more intuitive for me.
这是我根据您的功能使用的。我更喜欢使用步骤而不是百分比,因为它对我来说更直观。
For example, 20% of a 200 blue value is much different than 20% of a 40 blue value.
例如,200 蓝值的 20% 与 40 蓝值的 20% 大不相同。
Anyways, here's my modification, thanks for your original function.
无论如何,这是我的修改,感谢您的原始功能。
function adjustBrightness(col, amt) {
var usePound = false;
if (col[0] == "#") {
col = col.slice(1);
usePound = true;
}
var R = parseInt(col.substring(0,2),16);
var G = parseInt(col.substring(2,4),16);
var B = parseInt(col.substring(4,6),16);
// to make the colour less bright than the input
// change the following three "+" symbols to "-"
R = R + amt;
G = G + amt;
B = B + amt;
if (R > 255) R = 255;
else if (R < 0) R = 0;
if (G > 255) G = 255;
else if (G < 0) G = 0;
if (B > 255) B = 255;
else if (B < 0) B = 0;
var RR = ((R.toString(16).length==1)?"0"+R.toString(16):R.toString(16));
var GG = ((G.toString(16).length==1)?"0"+G.toString(16):G.toString(16));
var BB = ((B.toString(16).length==1)?"0"+B.toString(16):B.toString(16));
return (usePound?"#":"") + RR + GG + BB;
}
回答by James Khoury
have you thought about an rgb > hsl conversion? then just move the Luminosity up and down? thats the way I would go.
你有没有想过 rgb > hsl 转换?然后只是上下移动亮度?这就是我要走的路。
A quick look for some algorithms got me the following sites.
快速查找一些算法让我找到了以下网站。
PHP: http://serennu.com/colour/rgbtohsl.php
PHP:http: //serennu.com/colour/rgbtohsl.php
Javascript:
http://mjiHymanson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript
Javascript:http:
//mjiHymanson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript
EDITthe above link is no longer valid. You can view git hub for the page sourceor the gist
编辑以上链接不再有效。可以查看页面源码或者gist的git hub
Alternatively another StackOverflow questionmight be a good place to look.
或者另一个 StackOverflow问题可能是一个很好的地方。
Even though this is not the right choice for the OP the following is an approximation of the code I was originally suggesting. (Assuming you have rgb/hsl conversion functions)
尽管这不是 OP 的正确选择,但以下是我最初建议的代码的近似值。(假设你有 rgb/hsl 转换功能)
var SHADE_SHIFT_AMOUNT = 0.1;
function lightenShade(colorValue)
{
if(colorValue && colorValue.length >= 6)
{
var redValue = parseInt(colorValue.slice(-6,-4), 16);
var greenValue = parseInt(colorValue.slice(-4,-2), 16);
var blueValue = parseInt(colorValue.slice(-2), 16);
var hsl = rgbToHsl(redValue, greenValue, blueValue);
hsl[2]= Math.min(hsl[2] + SHADE_SHIFT_AMOUNT, 1);
var rgb = hslToRgb(hsl[0], hsl[1], hsl[2]);
return "#" + rgb[0].toString(16) + rgb[1].toString(16) + rgb[2].toString(16);
}
return null;
}
function darkenShade(colorValue)
{
if(colorValue && colorValue.length >= 6)
{
var redValue = parseInt(colorValue.slice(-6,-4), 16);
var greenValue = parseInt(colorValue.slice(-4,-2), 16);
var blueValue = parseInt(colorValue.slice(-2), 16);
var hsl = rgbToHsl(redValue, greenValue, blueValue);
hsl[2]= Math.max(hsl[2] - SHADE_SHIFT_AMOUNT, 0);
var rgb = hslToRgb(hsl[0], hsl[1], hsl[2]);
return "#" + rgb[0].toString(16) + rgb[1].toString(16) + rgb[2].toString(16);
}
return null;
}
This assumes:
这假设:
- You have functions
hslToRgb
andrgbToHsl
. - The parameter
colorValue
is a string in the form #RRGGBB
- 你有函数
hslToRgb
和rgbToHsl
. - 参数
colorValue
是#RRGGBB形式的字符串
Although if we are discussing css there is a syntax for specifying hsl/hslafor IE9/Chrome/Firefox.
虽然如果我们讨论 css,有一个语法可以为 IE9/Chrome/Firefox指定hsl/hsla。
回答by Cool Acid
I tried your function and there was a little bug: If some final 'r' value is 1 digit only, the result comes up like: 'a0a0a' when the right value is '0a0a0a', for example. I just quick-fixed it by adding this instead of your return:
我尝试了你的函数,但有一个小错误:例如,如果某个最终的 'r' 值只有 1 位数字,则结果如下:'a0a0a' 当正确的值是 '0a0a0a' 时。我只是通过添加这个而不是你的回报来快速修复它:
var rStr = (r.toString(16).length < 2)?'0'+r.toString(16):r.toString(16);
var gStr = (g.toString(16).length < 2)?'0'+g.toString(16):g.toString(16);
var bStr = (b.toString(16).length < 2)?'0'+b.toString(16):b.toString(16);
return (usePound?"#":"") + rStr + gStr + bStr;
Maybe it's not so nice but it do the work. Great function, BTW. Just what I needed. :)
也许它不是那么好,但它可以完成工作。很棒的功能,顺便说一句。正是我所需要的。:)
回答by user1618171
C# Version... note that I am getting color strings in this format #FF12AE34, and need to cut out the #FF.
C# 版本...请注意,我以这种格式获取颜色字符串#FF12AE34,并且需要剪掉#FF。
private string GetSmartShadeColorByBase(string s, float percent)
{
if (string.IsNullOrEmpty(s))
return "";
var r = s.Substring(3, 2);
int rInt = int.Parse(r, NumberStyles.HexNumber);
var g = s.Substring(5, 2);
int gInt = int.Parse(g, NumberStyles.HexNumber);
var b = s.Substring(7, 2);
int bInt = int.Parse(b, NumberStyles.HexNumber);
var t = percent < 0 ? 0 : 255;
var p = percent < 0 ? percent*-1 : percent;
int newR = Convert.ToInt32(Math.Round((t - rInt) * p) + rInt);
var newG = Convert.ToInt32(Math.Round((t - gInt) * p) + gInt);
var newB = Convert.ToInt32(Math.Round((t - bInt) * p) + bInt);
return String.Format("#{0:X2}{1:X2}{2:X2}", newR, newG, newB);
}
回答by Torbj?rn Josefsson
I wanted to change a color to a specificbrightness level - no matter what brightness the color was before - here's a simple JS function that seems to work well, although I'm sure it could be shorter
我想将颜色更改为特定的亮度级别 - 无论颜色之前的亮度是多少 - 这是一个简单的 JS 函数,它似乎运行良好,尽管我确定它可以更短
function setLightPercentage(col: any, p: number) {
const R = parseInt(col.substring(1, 3), 16);
const G = parseInt(col.substring(3, 5), 16);
const B = parseInt(col.substring(5, 7), 16);
const curr_total_dark = (255 * 3) - (R + G + B);
// calculate how much of the current darkness comes from the different channels
const RR = ((255 - R) / curr_total_dark);
const GR = ((255 - G) / curr_total_dark);
const BR = ((255 - B) / curr_total_dark);
// calculate how much darkness there should be in the new color
const new_total_dark = ((255 - 255 * (p / 100)) * 3);
// make the new channels contain the same % of available dark as the old ones did
const NR = 255 - Math.round(RR * new_total_dark);
const NG = 255 - Math.round(GR * new_total_dark);
const NB = 255 - Math.round(BR * new_total_dark);
const RO = ((NR.toString(16).length === 1) ? "0" + NR.toString(16) : NR.toString(16));
const GO = ((NG.toString(16).length === 1) ? "0" + NG.toString(16) : NG.toString(16));
const BO = ((NB.toString(16).length === 1) ? "0" + NB.toString(16) : NB.toString(16));
return "#" + RO + GO + BO;}
回答by Jason Williams
The following method will allow you to lighten or darken the exposure value of a Hexadecimal (Hex) color string:
以下方法将允许您使十六进制 (Hex) 颜色字符串的曝光值变亮或变暗:
private static string GetHexFromRGB(byte r, byte g, byte b, double exposure)
{
exposure = Math.Max(Math.Min(exposure, 1.0), -1.0);
if (exposure >= 0)
{
return "#"
+ ((byte)(r + ((byte.MaxValue - r) * exposure))).ToString("X2")
+ ((byte)(g + ((byte.MaxValue - g) * exposure))).ToString("X2")
+ ((byte)(b + ((byte.MaxValue - b) * exposure))).ToString("X2");
}
else
{
return "#"
+ ((byte)(r + (r * exposure))).ToString("X2")
+ ((byte)(g + (g * exposure))).ToString("X2")
+ ((byte)(b + (b * exposure))).ToString("X2");
}
}
For the last parameter value in GetHexFromRGB(), Pass in a double value somewhere between -1 and 1 (-1 is black, 0 is unchanged, 1 is white):
对于 GetHexFromRGB() 中的最后一个参数值,传入一个介于 -1 和 1 之间的双精度值(-1 是黑色,0 不变,1 是白色):
// split color (#e04006) into three strings
var r = Convert.ToByte("e0", 16);
var g = Convert.ToByte("40", 16);
var b = Convert.ToByte("06", 16);
GetHexFromRGB(r, g, b, 0.25); // Lighten by 25%;
回答by user2655360
I've long wanted to be able to produce tints/shades of colours, here is my JavaScript solution:
我一直希望能够产生色调/色调,这是我的 JavaScript 解决方案:
const varyHue = function (hueIn, pcIn) {
const truncate = function (valIn) {
if (valIn > 255) {
valIn = 255;
} else if (valIn < 0) {
valIn = 0;
}
return valIn;
};
let red = parseInt(hueIn.substring(0, 2), 16);
let green = parseInt(hueIn.substring(2, 4), 16);
let blue = parseInt(hueIn.substring(4, 6), 16);
let pc = parseInt(pcIn, 10); //shade positive, tint negative
let max = 0;
let dif = 0;
max = red;
if (pc < 0) { //tint: make lighter
if (green < max) {
max = green;
}
if (blue < max) {
max = blue;
}
dif = parseInt(((Math.abs(pc) / 100) * (255 - max)), 10);
return leftPad(((truncate(red + dif)).toString(16)), '0', 2) + leftPad(((truncate(green + dif)).toString(16)), '0', 2) + leftPad(((truncate(blue + dif)).toString(16)), '0', 2);
} else { //shade: make darker
if (green > max) {
max = green;
}
if (blue > max) {
max = blue;
}
dif = parseInt(((pc / 100) * max), 10);
return leftPad(((truncate(red - dif)).toString(16)), '0', 2) + leftPad(((truncate(green - dif)).toString(16)), '0', 2) + leftPad(((truncate(blue - dif)).toString(16)), '0', 2);
}
};