如何计算所需的色相旋转以生成特定的颜色?


75

我有一张白色图片,正在用作div的背景,并且我想进行着色以匹配主题的主色。我知道我可以做到:

filter: sepia() saturate(10000%) hue-rotate(30deg);

并循环hue-rotate查找颜色,但是可以预先计算出该值吗?鉴于指定的十六进制值非常暗,我想我也需要包括invert(%)过滤器。

给定十六进制值,#689d94我需要执行什么数学运算来计算期望值hue-rotateinvert将我的白色背景图像转换为相同颜色的值?

编辑

这是div带有绿色过滤的白色背景图像的a的代码段。这里的窍门div是,被过滤的是整个对象,而不仅仅是图像。如果要div在文本中输入一些文本,则文本颜色也会变为绿色。

div {
  background:url(http://richard.parnaby-king.co.uk/basket.svg) no-repeat scroll 0 0 transparent;
  background-size:5em;
  width:5em;
  height:5em;
  -webkit-filter: invert(25%) sepia() saturate(100000%) hue-rotate(174deg);
  filter: invert(25%) sepia() saturate(100000%) hue-rotate(174deg);
}
<div>
  </div>


是的,它是实际的背景图像。
理查德·帕纳比·金

然后(再次进行AFAIK)..不可能,将滤镜应用于实际图像。
Paulie_D 2015年

您对此问题施加了哪些限制?我认为使用filter:url(#mySvgFilter)或多或少可以实现。那将需要能够在页面上的某个位置包含svg元素,或在某个位置承载SVG文件。那将是一个可行的解决方案吗?奇怪的是,使用颜色矩阵时我无法获得完全匹配的颜色(尽管它们应该匹配),但这可能是我误解了与混合模式有关的东西。另外,如果我要问的话,您要解决的基本问题是什么?
Johan Persson

最初,我试图通过仅使用一个svg图像(该篮子在页面的其他位置使用了)来减少用户需要发出的http请求数量,而我只是想使用CSS更改颜色。最终,我确实使用了另外两张图像(一张用于上面的深绿色,一张用于黑色),但这仍然是我要寻找答案的问题。至于限制-在十六进制输入的情况下,我正在寻找可以遵循的一系列步骤或过程,可以为我提供用于为白色图像着色的过滤器和值的列表。
理查德·帕纳比·金

是否可以使用在线SVG过滤器?
理查德·帕纳比·金

Answers:


94

在这种情况下,关键是定义初始颜色。从白色到黑色或任何灰度在技术上都不是实际的颜色-您不能使其饱和或旋转。您必须以某种方式对其进行“着色”,而棕褐色滤镜是唯一进行某种形式着色的滤镜。

如果您的图像是纯100%红色的,会更容易。然后,您可以直接添加目标度,并使用HSL作为目标来调整饱和度和亮度。对于白色起始点,第一步是转换并定义中间色,以便稍后我们可以对其进行饱和和旋转。

首先让白色图像变暗并应用棕褐色以获得“基础”颜色,我们可以使用:

filter: brightness(50%) sepia(1);

这将产生大约RGB颜色值:

rgb(178, 160, 128)

第二步是将其转换为HSL颜色空间,从而得到:

hsl(38, 24.5%, 60%);

基色结果

div {
  background:url(http://richard.parnaby-king.co.uk/basket.svg) no-repeat;
  background-size:5em;
  width:5em;
  height:5em;
  -webkit-filter: brightness(50%) sepia(1);
  filter: brightness(50%) sepia(1);
}
<div></div>

将基本色转换为目标色

这两个第一步是静态的,每当我们需要查找目标调整时,其结果都将被重用(棕褐色的实际值在SVG过滤器规范中定义)。

现在,我们需要计算需要应用到该基础颜色的颜色以获得目标颜色。首先将目标颜色(例如问题中给出的#689d94)转换为HSL:

hsl(170, 21.3%, 51.2%);

然后,我们必须计算两者之间的差异。色调是通过简单地从目标中减去基数来计算的。饱和度和明度相同,但是由于我们假设基本值是100%,所以我们需要从100%中减去结果,最后得出累加值:

H:  170 - 38             ->  132°
S:  100 + (24.5 - 21.3)  ->  103.2%  (relative to base 100% =  3.2%)
L:  100 + (51.2 - 60.0)  ->   91.2%  (relative to base 100% = -8.8%)

通过将这些值附加到现有过滤器上,将其转换为过滤器字符串,然后在div上进行设置:

/*      ------ base color ------  -------  new target -------------------------------*/
filter: brightness(50%) sepia(1)  hue-rotate(132deg) saturate(103.2%) brightness(91.2%);

并设置它,您可能会假设已声明filter和divElement来执行以下操作:

...
filter = "brightness(0.5) sepia(1) hue-rotate(132deg) saturate(103.2%) brightness(91.2%)";
divElement.style.filter = filter;
divElement.style.webkitFilter = filter;

请注意,由于RGB表示为整数,而HSL是浮点数,因此可能会产生舍入误差,因此实际结果可能不准确,但应该非常接近。

现场例子

div {
  background:url(http://richard.parnaby-king.co.uk/basket.svg) no-repeat;
  background-size:5em;
  width:5em;
  height:5em;
  -webkit-filter: 
      brightness(50%) sepia(1) hue-rotate(132deg) saturate(103.2%) brightness(91.2%);
  filter: 
      brightness(50%) sepia(1) hue-rotate(132deg) saturate(103.2%) brightness(91.2%);
}
<div></div>
<span style="font:14px sans-serif;padding:7px;color:#fff;background:#689d94">
Target color</span>

可行的替代选择是:

  • 使用已设置的颜色预定义SVG。
  • 直接在JavaScript中使用HSL / RGB,并直接使用形状的颜色修改SVG树,而不是使用滤镜。过滤器在性能上是昂贵的,特别是如果许多过滤器按此链接在一起并且它们是页面的主要组成部分时,尤其如此。所有浏览器均不支持它们。


@ K3N我在这里有一个非常相似的问题:stackoverflow.com/questions/45901333/…。也许您有答案?谢谢!
艾米利奥(Emilio)

11
不幸的是,这个答案是错误的。假设色相旋转在HSL空间中运行。它不是。CSS hue-rotate基于SVG滤镜规范中定义的基础hue-rotate-它没有HSL颜色空间的概念。较差的结果不是浮点逼近的结果,而是色相旋转确实使R / G / B的数量不相等,从而严重刺破了颜色的剪切,尤其是“极端”的剪切。
Michael Mullany

2
这是一个不错的尝试,但完全是误导。
shabunc

25

接受的答案是错误的。色相旋转不节省饱和度或亮度,您必须进行疯狂的数学运算才能得出正确的值。最简单的方法(将导致正确的结果)是做一个引用SVG过滤器的CSS过滤器。SVG过滤器中的feColorMatrix原语允许您直接选择颜色-就像这样。以您的颜色#424242-将每种颜色的十六进制值除以#FF(.257),然后将它们放在颜色矩阵的前三行,即第五列中。像这样:

div {
  background:url(http://richard.parnaby-king.co.uk/basket.svg) no-repeat scroll 0 0 transparent;
  background-size:5em;
  width:5em;
  height:5em;
  -webkit-filter: url(#colorize);
  filter: url(#colorize);
}
<div>
  </div>

<svg>
<defs>
<filter id="colorize" color-interpolation-filters="sRGB">
<feColorMatrix type="matrix" values="0 0 0 0 .257
                                 0 0 0 0 .257
                                 0 0 0 0 .257
                                 0 0 0 1 0"/>
 
/filter>
</defs>
</svg>


这看起来是一个不错的解决方案。但是,您能指出我如何从#424242和#FF获取.257,.257,.257吗?我试着去一个十六进制计算器,做十六进制42进制FF分,它只是告诉我的十六进制值:0余数:42,十进制值:0余:66
mpavey

2
十六进制#42 =十进制4 * 16 + 2 = 66. 66/256 =
.257

@MichaelMullany为什么要除以256,而不是255?
shabunc

应该是255-对不起。
Michael Mullany

0

如果正在使用svg,则...

您可以使用某些文本编辑器副本打开svg文件,然后将其粘贴到html文件中,然后根据需要更改路径颜色。

在下面的示例代码中,...我只是更改了中心环的路径颜色。希望这可以帮助..

        var imgg =document.getElementById("path");
        imgg.style="fill:#424242";
   
<html>
<body>
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg id="imgg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_1" x="0px" y="0px" viewBox="0 0 296.838 296.838" style="enable-background:new 0 0 296.838 296.838;" xml:space="preserve" width="512px" height="512px">
<g>
	<path  d="M58.733,64.566L41.763,47.596C14.832,74.526,0,110.333,0,148.419s14.832,73.893,41.763,100.823l16.971-16.971   C36.335,209.874,24,180.095,24,148.419S36.335,86.964,58.733,64.566z" fill="#91DC5A"/>
	<path d="M82.137,81.969c-17.75,17.748-27.525,41.348-27.525,66.45s9.775,48.702,27.525,66.45l16.971-16.971   c-13.218-13.216-20.496-30.788-20.496-49.479s7.278-36.264,20.496-49.48L82.137,81.969z" fill="#91DC5A"/>
	<path d="M255.075,47.596l-16.971,16.971c22.399,22.397,34.733,52.177,34.733,83.853s-12.335,61.455-34.733,83.852l16.971,16.971   c26.931-26.931,41.763-62.737,41.763-100.823S282.006,74.526,255.075,47.596z" fill="#91DC5A"/>
	<path d="M214.701,81.969L197.73,98.939c13.218,13.216,20.496,30.788,20.496,49.48s-7.278,36.264-20.496,49.479l16.971,16.971   c17.75-17.748,27.525-41.348,27.525-66.45S232.451,99.717,214.701,81.969z" fill="#91DC5A"/>
	<path id="path" d="M148.586,114.789c-8.607,0-17.212,3.284-23.78,9.851c-13.131,13.133-13.131,34.424,0,47.559   c6.568,6.566,15.174,9.851,23.78,9.851c8.606,0,17.212-3.284,23.779-9.851c13.131-13.135,13.131-34.426,0-47.559   C165.798,118.073,157.192,114.789,148.586,114.789z M155.395,155.228c-2.454,2.454-5.319,2.821-6.809,2.821   c-1.489,0-4.356-0.367-6.808-2.818c-3.755-3.756-3.755-9.867-0.003-13.619c2.455-2.455,5.321-2.822,6.811-2.822   c1.489,0,4.354,0.367,6.808,2.82C159.147,145.363,159.147,151.475,155.395,155.228z" fill="#91DC5A"/>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>
    
    
</body>
</html>

对于背景图片

        var myimg='url(\'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_1" x="0px" y="0px" viewBox="0 0 296.838 296.838" style="enable-background:new 0 0 296.838 296.838;" xml:space="preserve" width="512px" height="512px"><g><path  d="M58.733,64.566L41.763,47.596C14.832,74.526,0,110.333,0,148.419s14.832,73.893,41.763,100.823l16.971-16.971   C36.335,209.874,24,180.095,24,148.419S36.335,86.964,58.733,64.566z" fill="#91DC5A"/><path d="M82.137,81.969c-17.75,17.748-27.525,41.348-27.525,66.45s9.775,48.702,27.525,66.45l16.971-16.971   c-13.218-13.216-20.496-30.788-20.496-49.479s7.278-36.264,20.496-49.48L82.137,81.969z" fill="#91DC5A"/><path d="M255.075,47.596l-16.971,16.971c22.399,22.397,34.733,52.177,34.733,83.853s-12.335,61.455-34.733,83.852l16.971,16.971   c26.931-26.931,41.763-62.737,41.763-100.823S282.006,74.526,255.075,47.596z" fill="#91DC5A"/><path d="M214.701,81.969L197.73,98.939c13.218,13.216,20.496,30.788,20.496,49.48s-7.278,36.264-20.496,49.479l16.971,16.971   c17.75-17.748,27.525-41.348,27.525-66.45S232.451,99.717,214.701,81.969z" fill="#91DC5A"/><path d="M148.586,114.789c-8.607,0-17.212,3.284-23.78,9.851c-13.131,13.133-13.131,34.424,0,47.559   c6.568,6.566,15.174,9.851,23.78,9.851c8.606,0,17.212-3.284,23.779-9.851c13.131-13.135,13.131-34.426,0-47.559   C165.798,118.073,157.192,114.789,148.586,114.789z M155.395,155.228c-2.454,2.454-5.319,2.821-6.809,2.821   c-1.489,0-4.356-0.367-6.808-2.818c-3.755-3.756-3.755-9.867-0.003-13.619c2.455-2.455,5.321-2.822,6.811-2.822   c1.489,0,4.354,0.367,6.808,2.82C159.147,145.363,159.147,151.475,155.395,155.228z" fill="#91DC5A"/></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g></svg> \')';
        
        document.getElementById("mydiv").style.backgroundImage =myimg ;  
        
        
        
        //changing color according to theme .. new theme color :#424242
        myimg=myimg.replace(/#91DC5A/g,"#424242");
       document.getElementById("mydiv").style.backgroundImage =myimg ; 
             div {

  background-size:5em;
  width:5em;
  height:5em;
  
}
<html>
<body>

    
    <div id="mydiv"></div>
<span style="font:14px sans-serif;padding:7px;color:#fff;background:#689d94">
Target color</span>
   
  
    
</body>
</html>


必须是背景图片。
理查德·帕纳比·金

@ RichardParnaby-King补充背景图像的情况下也..我会用的z-index制作图像背景..反正..我已经做了背景图像的解决方法
阿紫

svg也可以用作背景图像。
Erkin AlpGüney20年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.