这是我正在研究的一个函数,它以编程方式将十六进制颜色变亮或变暗特定量。只需传入一个像 "3F6D2A"
这样的字符串作为颜色 (col
) 和一个 base10 整数 (amt
) 来表示变亮或变暗的量。要变暗,请传入一个负数(即 -20
)。
我这样做的原因是因为我找到的所有解决方案,到目前为止,它们似乎使问题过于复杂。我有一种感觉,只需几行代码就可以完成。如果您发现任何问题或进行任何调整以加快速度,请告诉我。
函数 LightenDarkenColor(col, amt) { col = parseInt(col, 16);返回 (((col & 0x0000FF) + amt) | ((((col >> 8) & 0x00FF) + amt) << 8) | (((col >> 16) + amt) << 16)).toString (16); } // 测试 console.log( LightenDarkenColor("3F6D2A",40) );
对于开发使用,这里是一个更易于阅读的版本:
函数 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);返回 newColor.toString(16); } // 测试 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);
我想我的主要问题是,我在这里正确吗?这不包括一些(正常)情况吗?
嗯,这个答案已经变成了它自己的野兽。许多新版本,它变得越来越愚蠢。非常感谢所有对此答案的众多贡献者。但是,为了让大众保持简单。我将此答案演变的所有版本/历史存档到我的 github。并在 StackOverflow 上使用最新版本重新开始。特别感谢 Mike 'Pomax' Kamermans 提供此版本。他给了我新的数学。
此函数 (pSBC
) 将采用 HEX 或 RGB 网络颜色。 pSBC
可以更深或更浅地对其进行着色,或者将其与第二种颜色混合,也可以将其直接传递,但将其从十六进制转换为 RGB (Hex2RGB) 或将 RGB 转换为十六进制 (RGB2Hex)。您甚至都不知道您使用的是什么颜色格式。
这运行得非常快,可能是最快的,尤其是考虑到它的许多特性。这是一个很长的时间。在我的 github 上查看整个故事。如果您想要绝对最小和最快的着色或混合方式,请参阅下面的微功能并使用 2 线速度恶魔之一。它们非常适合激烈的动画,但这里的这个版本对于大多数动画来说已经足够快了。
此功能使用对数混合或线性混合。但是,它不会转换为 HSL 以适当地使颜色变亮或变暗。因此,此函数的结果将不同于使用 HSL 的那些更大且更慢的函数。
jsFiddle 与 pSBC github > pSBC Wiki
特征:
自动检测并接受字符串形式的标准十六进制颜色。例如:“#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 (from) 颜色如何;如果存在,返回的颜色将始终采用 c1 (to) 颜色的颜色格式。如果没有 c1 (to) 颜色,则将“c”作为 c1 颜色传入,它会着色并转换 c0 颜色。如果只需要转换,则也将 0 作为百分比 (p) 传入。如果省略 c1 颜色或传入非字符串,则不会转换。
辅助函数也被添加到全局中。 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 输出,当具有 alpha 通道的颜色被传递到 c0(从)和/或 c1(到)时,它会在 rgb() 上输出 rgba()。
添加了小错误检查。这并不完美。它仍然可能崩溃或产生乱码。但它会抓住一些东西。基本上,如果结构在某些方面是错误的,或者百分比不是数字或超出范围,它将返回 null。一个例子:pSBC(0.5,"salt") == null,因为它认为#salt 是一种有效的颜色。删除以return null结尾的四行;删除此功能并使其更快更小。
使用对数混合。为 l (第 4 个参数)传递 true 以使用线性混合。
代码:
// 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] => 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}
下图将有助于显示两种混合方法的区别:
https://i.imgur.com/FBe90R8.png
微函数
如果你真的想要速度和大小,你将不得不使用 RGB 而不是 HEX。 RGB 更直接、更简单,HEX 写入速度太慢,并且对于简单的两行代码(即,它可能是 3、4、6 或 8 位 HEX 代码)来说有太多的风格。您还需要牺牲一些功能,没有错误检查,没有 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:")");
}
想要更多信息?阅读 github 上的完整文章。
PT
(PS如果有人有其他混合方法的数学,请分享。)
我提出了一个非常适合我的解决方案:
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;
}
示例减轻:
shadeColor("#63C6FF",40);
示例变暗:
shadeColor("#63C6FF",-40);
R = ((R<255)?R:255).toString(16);
,然后再做 R = R.length==1 ? "0"+R : R
。我不确定 toUpperCase 的意义何在?
var R = parseInt(color.substring(1, 3), 16) var G = parseInt(color.substring(3, 5), 16) var B = parseInt(color.substring(5, 7), 16) if (R == 0) R = 32; if (G == 0) G = 32; if (B == 0) B = 32;
这是一个基于埃里克回答的超级简单的单线
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));
}
例子:
adjust('#ffffff', -20) => "#ebebeb"
adjust('000000', 20) => "#141414"
\w\w
(与 #
不匹配)来缩短它,而不是删除并重新添加 #
。我也不太明白你为什么要添加 0
然后删除它?这是我没有关注的一些 JS 东西吗(你已经在使用 toString()
,所以你不需要强制转换它?)无论如何,我最终得到了以下内容,它的行为似乎相同:{ 6}
'0'+
和 substr(-2)
用于 0 到 15 之间的那些数字,它们在十六进制中只有一位,因此会给出格式错误的十六进制颜色字符串。他在前面加上“0”并保留最后两位数字,这样 9 就变成了“09”,而不仅仅是“9”。不过第一点很好! 👍
我在这里加上我的 2 美分,这是不同答案的令人满意的小组合:
const colorShade = (col, amt) => {
col = col.replace(/^#/, '')
if (col.length === 3) col = col[0] + col[0] + col[1] + col[1] + col[2] + col[2]
let [r, g, b] = col.match(/.{2}/g);
([r, g, b] = [parseInt(r, 16) + amt, parseInt(g, 16) + amt, parseInt(b, 16) + amt])
r = Math.max(Math.min(255, r), 0).toString(16)
g = Math.max(Math.min(255, g), 0).toString(16)
b = Math.max(Math.min(255, b), 0).toString(16)
const rr = (r.length < 2 ? '0' : '') + r
const gg = (g.length < 2 ? '0' : '') + g
const bb = (b.length < 2 ? '0' : '') + b
return `#${rr}${gg}${bb}`
}
接受或不以 #
开头的颜色,有 6 个字符或 3 个字符。
使用示例:colorShade('#54b946', -40)
这是 4 种颜色的输出,每种颜色有 3 种浅色和 3 种深浅(这里的数量是 40 的倍数)。
https://i.stack.imgur.com/QY7ja.png
这是我根据您的功能使用的。我更喜欢使用步骤而不是百分比,因为它对我来说更直观。
例如,200 蓝色值的 20% 与 40 蓝色值的 20% 有很大不同。
无论如何,这是我的修改,感谢您的原始功能。
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;
}
我尝试了你的函数,但有一个小错误:例如,如果某个最终的 'r' 值仅为 1 位,则结果如下:例如,当正确的值为 '0a0a0a' 时,结果为:'a0a0a'。我只是通过添加这个而不是你的回报来快速修复它:
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;
也许它不是那么好,但它确实有效。很棒的功能,顺便说一句。正是我需要的。 :)
基于 David Sherret 和 Pablo,上面的答案将解决方案转换为更安全的 Typescript 版本
/**
* @param color Hex value format: #ffffff or ffffff
* @param decimal lighten or darken decimal value, example 0.5 to lighten by 50% or 1.5 to darken by 50%.
*/
static shadeColor(color: string, decimal: number): string {
const base = color.startsWith('#') ? 1 : 0;
let r = parseInt(color.substring(base, 3), 16);
let g = parseInt(color.substring(base + 2, 5), 16);
let b = parseInt(color.substring(base + 4, 7), 16);
r = Math.round(r / decimal);
g = Math.round(g / decimal);
b = Math.round(b / decimal);
r = (r < 255)? r : 255;
g = (g < 255)? g : 255;
b = (b < 255)? b : 255;
const rr = ((r.toString(16).length === 1)? `0${r.toString(16)}` : r.toString(16));
const gg = ((g.toString(16).length === 1)? `0${g.toString(16)}` : g.toString(16));
const bb = ((b.toString(16).length === 1)? `0${b.toString(16)}` : b.toString(16));
return `#${rr}${gg}${bb}`;
}
您是否考虑过 rgb > hsl 转换?然后只是上下移动亮度?这就是我要走的路。
快速浏览一些算法让我找到了以下站点。
PHP:http://serennu.com/colour/rgbtohsl.php
编辑以上链接不再有效。您可以查看 page source 或 gist 的 git hub
或者,另一个 StackOverflow question 可能是一个不错的地方。
尽管这不是 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;
}
这假设:
你有函数 hslToRgb 和 rgbToHsl。参数 colorValue 是 #RRGGBB 形式的字符串
虽然如果我们在讨论 css,有一种语法可以为 IE9/Chrome/Firefox 指定 hsl/hsla。
你的方法没问题 :) 我稍微简化了你的最短版本(饱和控制看起来 here)
(col,amt)=> (+('0x'+col)+amt*0x010101).toString(16).padStart(6,0)
// 类似于 OP 最短版本,我们这里没有 # 和颜色范围检查 var LightenDarkenColor = (col,amt) => (+('0x'+col)+amt*0x010101).toString(16).padStart(6 ,0); // ------ // 测试 // ------ function update() { let c= col.value.padEnd(6,'0').slice(0,6);让颜色 = '#'+LightenDarkenColor(c, +amt.value); oldColor.innerHTML = '旧:#'+c; oldColor.style = `背景:#${c}`; newColor.innerHTML = '新建:'+颜色 newColor.style = `背景:${color}`; } 更新(); .box{ 宽度:100px;高度:100px;边距:10px;显示:内联块}
< div id="oldColor" class="box">
带有 # 和颜色范围检查的版本
// # 和颜色范围检查 var LightenDarkenColor = (col,amt) => '#'+col.slice(1).match(/../g) .map(x=>(x=+`0x${ x}`+amt,x<0?0:(x>255?255:x)) .toString(16).padStart(2,0)).join``; // ------ // 测试 // ------ function update() { let c= col.value.padEnd(6,'0').slice(0,7);让颜色 = LightenDarkenColor(c, +amt.value); oldColor.innerHTML = '旧:'+c; oldColor.style = `背景:${c}`; newColor.innerHTML = '新建:'+颜色 newColor.style = `背景:${color}`; } 更新(); .box{ 宽度:100px;高度:100px;边距:10px;显示:内联块}
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);
}
int
和两个 vars
用于相同类型的数据。
我想将颜色更改为特定的亮度级别 - 无论颜色之前的亮度是多少 - 这是一个简单的 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;}
p
的范围是 0-100
?我什至不知道如何正确定义 RGB 中的亮度,这是 HSL 的事情。例如,#FF00FF
是否比 #FF0000
亮?如果是这样,那就意味着洋红色的亮度是红色的两倍。因此,使用纯红色测试。传入纯红色 #FF0000
,设置为 50% 亮度,我们得到 #FF4040
,对吗?我猜想使红色亮度为 50%,我们会变得更暗,因为它已经完全亮了.. 如 #800000
或 150% 亮度将是 #FF8080
。粉红色是不是更亮的红色?还是红色已经完全亮了?
L
通道实际上就是亮度。我的 [个人心理] 问题是,对我来说,#FF0000
是完全明亮的。 #FF4040
更轻但不更亮......对我来说,更轻意味着更接近白色,就像粉红色一样。亮度是它得到了多少,它得到了全红色,所以红色,是全亮的。因此,#FF0000
不能变得更亮......而是......更轻......也许我只是一个怪胎,哈哈!我真的不知道色彩理论,所以,我真的只是在说我的...
我只是使用了'#'前面的十六进制数字。
var x = 0xf0f0f0;
x=x+0xf00; //set this value as you wish programatically
document.getElementById("heading").style = 'background-color: #'+x.toString(16);
数字越大..颜色越浅
我在 C# 中需要它,它可以帮助 .net 开发人员
public static string LightenDarkenColor(string color, int amount)
{
int colorHex = int.Parse(color, System.Globalization.NumberStyles.HexNumber);
string output = (((colorHex & 0x0000FF) + amount) | ((((colorHex >> 0x8) & 0x00FF) + amount) << 0x8) | (((colorHex >> 0xF) + amount) << 0xF)).ToString("x6");
return output;
}
我用打字稿写的版本:
function changeColorLightness(color: number, lightness: number): number {
return (Math.max(0, Math.min(((color & 0xFF0000) / 0x10000) + lightness, 0xFF)) * 0x10000) +
(Math.max(0, Math.min(((color & 0x00FF00) / 0x100) + lightness, 0xFF)) * 0x100) +
(Math.max(0, Math.min(((color & 0x0000FF)) + lightness, 0xFF)));
}
解释:
export function changeColorLightness(color: number, lightness: number): number {
const r = (color & 0xFF0000) / 0x10**4;
const g = (color & 0x00FF00) / 0x10**2;
const b = (color & 0x0000FF);
const changedR = Math.max(0, Math.min(r + lightness, 0xFF));
const changedG = Math.max(0, Math.min(g + lightness, 0xFF));
const changedB = Math.max(0, Math.min(b + lightness, 0xFF));
return (changedR * 0x10**4) + (changedG * 0x10**2) + changedB;
}
用法:
changeColorLightness(0x00FF00, 0x50);
changeColorLightness(parseInt("#00FF00".replace('#',''), 16), 0x50);
changeColorLightness(0x00FF00, 127.5);
以下方法将允许您使十六进制 (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");
}
}
对于 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%;
缺乏对从 00 开始的颜色的支持,即“#000623”,但这里是修复
function lightenDarkenColor(colorCode, amount) {
let usePound = false;
if (colorCode[0] == "#") {
colorCode = colorCode.slice(1);
usePound = true;
}
const num = parseInt(colorCode, 16);
let r = (num >> 16) + amount;
if (r > 255) {
r = 255;
} else if (r < 0) {
r = 0;
}
let b = ((num >> 8) & 0x00FF) + amount;
if (b > 255) {
b = 255;
} else if (b < 0) {
b = 0;
}
let g = (num & 0x0000FF) + amount;
if (g > 255) {
g = 255;
} else if (g < 0) {
g = 0;
}
let color = (g | (b << 8) | (r << 16)).toString(16);
while (color.length < 6){
color = 0 + color;
}
return (usePound ? '#' : '') + color;
}
如何在 PHP 中简单地着色?
<?php
function shadeColor ($color='#cccccc', $percent=-25) {
$color = Str_Replace("#",Null,$color);
$r = Hexdec(Substr($color,0,2));
$g = Hexdec(Substr($color,2,2));
$b = Hexdec(Substr($color,4,2));
$r = (Int)($r*(100+$percent)/100);
$g = (Int)($g*(100+$percent)/100);
$b = (Int)($b*(100+$percent)/100);
$r = Trim(Dechex(($r<255)?$r:255));
$g = Trim(Dechex(($g<255)?$g:255));
$b = Trim(Dechex(($b<255)?$b:255));
$r = ((Strlen($r)==1)?"0{$r}":$r);
$g = ((Strlen($g)==1)?"0{$g}":$g);
$b = ((Strlen($b)==1)?"0{$b}":$b);
return (String)("#{$r}{$g}{$b}");
}
echo shadeColor(); // #999999
我做了一个优秀的 xcolor 库的移植来删除它的 jQuery 依赖。那里有很多功能,包括变亮和变暗颜色。
确实,将十六进制转换为 RGB 是一个完全独立于变亮或变暗颜色的功能。请保持干燥。在任何情况下,一旦你有了一个 RGB 颜色,你就可以将你想要的亮度级别和你拥有的亮度级别之间的差异添加到每个 RGB 值中:
var lightness = function(level) {
if(level === undefined) {
return Math.max(this.g,this.r,this.b)
} else {
var roundedLevel = Math.round(level) // fractions won't work here
var levelChange = roundedLevel - this.lightness()
var r = Math.max(0,this.r+levelChange)
var g = Math.max(0,this.g+levelChange)
var b = Math.max(0,this.b+levelChange)
if(r > 0xff) r = 0xff
if(g > 0xff) g = 0xff
if(b > 0xff) b = 0xff
return xolor({r: r, g: g, b: b})
}
}
var lighter = function(amount) {
return this.lightness(this.lightness()+amount)
}
有关更多来源,请参阅 https://github.com/fresheneesz/xolor。
我一直希望能够产生色调/色调,这是我的 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);
}
};
#
。对不起,如果它看起来像......“批准”......我将其视为同行评审。如果您不希望有人分析您的代码或提供反馈,我深表歉意。
不定期副业成功案例分享
tinycolor.darken(color,amount);
8
,则添加10%
你会得到8.8
,它会四舍五入到9
。然后从9
中取出9.09%
,得到8.1819
。哪个舍入到8
所以这是一个不好的例子。但它仍然说明您正在服用9
中的9.09%
而不是8.8
。因此,其中可能有一些数字与我在这里的示例不完全相同。'pSBCr' is not defined no-undef