以编程方式变亮或变暗十六进制颜色(或 RGB 和混合颜色)

2024-04-16

这是我正在开发的一个函数,用于以编程方式使十六进制颜色变亮或变暗特定的量。只需传入一个字符串,例如"3F6D2A"对于颜色(col) 和一个以 10 为基数的整数 (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);

我想我的主要问题是,我在这里正确吗?这不包括大多数(正常)情况吗?如果是这样,最快、最小的方法是什么?我想在动画和小环境中使用,所以速度是这里第一个最重要的因素,其次是大小,第三是准确性,可读性?嗯?不在要求清单上(抱歉,我知道你们中有一半人现在正在流泪!)。


好吧,这个答案已经成为它自己的野兽。新版本很多,时间越来越长了。非常感谢这个答案的所有贡献者。但是,为了让大众保持简单。我将这个答案演变的所有版本/历史存档到我的github https://github.com/PimpTrizkit/PJs/wiki/12.-Shade,-Blend-and-Convert-a-Web-Color-(pSBC.js)#stackoverflow-archive-begin。并在 StackOverflow 上使用最新版本重新开始。特别感谢迈克·“波马克斯”·卡默曼斯 https://stackoverflow.com/users/740553/mike-pomax-kamermans对于这个版本。他给了我新的数学。


这个函数(pSBC) 将采用 HEX 或 RGB 网页颜色。pSBC可以将其调暗或调亮,或者将其与第二种颜色混合,也可以将其直接传递,但从十六进制转换为 RGB (Hex2RGB) 或 RGB 到十六进制 (RGB2Hex)。您甚至不知道您正在使用什么颜色格式。

它运行得非常快,可能是最快的,特别是考虑到它的许多功能。这件事酝酿了很长时间。在我的网站上查看整个故事github https://github.com/PimpTrizkit/PJs/wiki/12.-Shade,-Blend-and-Convert-a-Web-Color-(pSBC.js)#stackoverflow-archive-begin。如果您想要绝对最小和最快的方式来着色或混合,请参阅下面的微功能并使用 2 线速度恶魔之一。它们非常适合激烈的动画,但这个版本对于大多数动画来说已经足够快了。

该函数使用对数混合或线性混合。但是,它不会转换为 HSL 来正确调亮或调暗颜色。所以,该函数的结果会有所不同来自那些使用 HSL 的更大且更慢的函数。

jsFiddle 与 pSBC https://jsfiddle.net/PimpTrizkit/a7ac0qvp/

github > pSBC 维基 https://github.com/PimpTrizkit/PJs/wiki/12.-Shade,-Blend-and-Convert-a-Web-Color-(pSBC.js)

特征:

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

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}

下图将有助于显示两种混合方法的差异:


微功能

如果您确实想要速度和大小,则必须使用 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:")");
}

想要更多信息吗?阅读完整的文章github https://github.com/PimpTrizkit/PJs/wiki/12.-Shade,-Blend-and-Convert-a-Web-Color-(pSBC.js).

PT

(P.s.如果有人知道另一种混合方法的数学,请分享。)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

以编程方式变亮或变暗十六进制颜色(或 RGB 和混合颜色) 的相关文章

  • 如何检测被覆盖的 CSS 属性?

    I can get all css properties for an element with document stylesheets but some of those are not active because those pro
  • 从 Internet Explorer 打印时的默认文件名

    使用 pdf 打印机打印网页 将页面另存为 pdf 时 Chrome 和 Firefox 都使用该页面
  • 从 Javascript 中的嵌套函数返回值[重复]

    这个问题在这里已经有答案了 考虑这段代码 缩短 function getSecret db transaction function transaction transaction executeSql SELECT FROM table
  • 在 JavaScript 中检测页面是否加载到 WKWebView 中

    如何使用 javascript 可靠地检测到页面已加载到 WKWebView 中 我希望能够检测到这些场景 iOS 和 WKWebView iOS 和 Safari not iOS 关于 UIWebView 有一个类似的问题here htt
  • javascript:全局变量泄漏

    每当我向 Firefox 提交插件时 我都会收到一封电子邮件 告诉我我的一些变量正在泄漏到全局范围内 一旦他们告诉我我解决了问题 但在那之前有什么方法 程序 来检查变量是否泄漏到全局范围内 Thanks Both JSLint http w
  • HTML 和 标签有什么区别?

    HEAD 标签和 BODY 标签有什么区别 大多数 HTML 书籍仅 简短 提及 and 标签 但它们消失得很快 它们会影响浏览器呈现网页的方式吗 另外 它们会影响 javascript 的运行顺序吗 我的意思是 如果我里面有一个javas
  • 有什么方法可以复制 div 的渲染 HTML 吗?

    我正在开发电子邮件签名生成器 我想通过按按钮复制最终签名 而不是手动选择签名并将其复制到剪贴板 这意味着我需要它们的图像 文本和样式 我尝试了几种变体 包括 w3schools 的变体 但没有成功 其中一些只是复制文本 但没有样式 例子 h
  • 在自动完成上添加 jQuery 延迟

    我正在尝试为应用程序创建 jQuery 自动完成 search input on keyup function search this val autocomplete div autocomplete get ajax search se
  • Chrome 开发工具命中代码但未命中断点

    我在 chrome 开发工具上启用了断点 并且在一行上有一个断点 我知道 chrome 正在运行 因为我将断点放在具有以下语句的行上 alert why is this not breaking 如果我在本地主机中找到该文件 则断点有效 断
  • Node.js Express 4.0 中的 res.render 回调参数的用途是什么?

    目的是什么res render回调参数 在什么情况下 由于模板已被指定为第一个参数 因此人们会想要使用这样的回调参数 这是文档中的代码 send the rendered view to the client res render inde
  • Javascript:我应该隐藏我的实现吗?

    作为一名 C 程序员 我有一个习惯 将可以而且应该私有的东西设为私有 当 JS 类型向我公开其所有私有部分时 我总是有一种奇怪的感觉 而且这种感觉并没有被 唤起 假设我有一个类型draw方法 内部调用drawBackground and d
  • 冒泡可用于图像加载事件吗?

    我可以用吗 window addEventListner 某种程度上来说 我所有的图像都有一个display none 图像加载后 我想设置display inline 这样我就可以规范下载图像时显示的内容 在这种情况下 我无法预加载图像
  • Socket IO 服务器到服务器

    服务器是否可以使用 Socket IO 连接到另一个服务器并被视为客户端 并让它加入房间 接收 io sockets in lobby emit 和更多 第一个服务器也在监听连接 消息 嘿 Brad 下面是我的完整 js 应用程序 供参考
  • 嵌套 DIV 的类似斑马的 CSS 样式

    我嵌套了 DIV 元素 但我不知道嵌套的级别 我需要每个都有与其父级不同的背景 创建类似斑马的颜色 我只使用两种背景 深色和白色 效果需要类似于在容器中设置奇数和偶数子级的样式 但在我的例子中 子级是嵌套的 我可以使用每个嵌套元素的规则来做
  • D3 向对象添加超链接?

    我正在尝试制作 D3 图 它将代表我网站的菜单 我尝试按照此处的其他指南添加超链接 但它们都不起作用 每个对象都会有一个不同的 URL 指向 主页 关于 联系方式等 如果添加超链接 我可以拖动对象吗 这意味着如果我按住单击 如果我单击该对象
  • 如何使用 jQuery 单击特定链接时打开引导导航选项卡的特定选项卡?

    我是 jquery 和 bootstrap 的新手 所以请考虑我的错误 我已经创建了一个用于登录和注册的 bootstrap 模式 它包含两个导航选项卡 称为登录和注册 我有两个按钮可以弹出相同的模态窗口 但在模态窗口内显示不同的选项卡 每
  • 在 Android Chrome 中隐藏 HTML5 音频/视频通知

    我的网络应用程序上有一个 HTML5 音频元素 在某些时候 我使用以下代码以编程方式停止播放 audioElement pause audioElement currentTime 0 播放音频时 我的 Android 设备 使用 Goog
  • 使用 File API polyfill 读取数据 URL

    我正在尝试使用文件 API 库 https github com mailru FileAPI https github com mailru FileAPI 作为不支持文件 API 的浏览器的后备 以便将文件作为数据 URL 读取并将其传
  • 如何为 jQuery 插件设置私有变量?

    我想创建一个简单的插件 它使用元素的文本作为默认值 或者您可以在调用插件时设置此值 但是 如果我不设置该值 并为多个元素调用插件 则默认值会成倍增加 function fn reText function options var setti
  • 使圆圈与 d3.js 上的多线匹配相同的颜色过滤?

    我有一个多线图 当按每种水果过滤时会更新 每条线条颜色对应不同的销售年份 在 的帮助下Shashank https stackoverflow com users 5569282 shashank 每个数据点线上的圆圈已添加到组中 而不是直

随机推荐