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

How to calculate required hue-rotate to generate specific colour?

我有一张白色图像用作 div 的背景,我想上色以匹配主题的主色。我知道我可以做到:

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

然后通过hue-rotate循环找到一种颜色,但是否可以提前计算出这个值?鉴于指定的十六进制值非常暗,我想我还需要包括 invert(%) 过滤器。

给定 #689d94 的十六进制值,我需要做哪些数学运算来计算所需的 hue-rotateinvert 值,以便将我的白色背景图像转换为相同的颜色?

编辑

这是一个 div 的片段,其中白色背景图片被过滤成绿色。这里的技巧是过滤整个 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>
<p style="background: #689d94">​</p>

本例的关键是定义初始颜色。白色、黑色或任何灰度在技术上都是实际颜色——您不能对其进行饱和或旋转。您必须以某种方式 "colorize" 它,棕褐色滤镜是唯一进行某种形式着色的滤镜。

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

首先让白色图像变暗并应用棕褐色以获得我们可以使用的 "base" 颜色:

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

这将产生大约的 RGB 颜色值:

rgb(178, 160, 128)

第二步是 convert that to HSL color-space,它给我们:

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>

正在将基色转换为目标颜色

这两个第一步是静态的,每次我们需要找到目标调整时都会重复使用其结果(sepia的实际值定义在SVG Filters specification).

现在我们需要计算我们需要将什么应用到这个基色以获得目标颜色。首先将目标颜色(例如问题中给出的#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%);

要设置它,假设过滤器和 div元素已经声明,您可能会做这样的事情:

...
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 树,而不是使用滤镜。过滤器在性能方面是昂贵的,特别是如果许多过滤器像这里一样被链接起来,并且它们还是页面的主要部分。所有浏览器都不支持它们。

如果使用 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>

接受的答案是错误的。色调旋转不会保留饱和度或亮度,您必须进行疯狂的数学运算才能得出正确的值。更简单的方法 - 将导致正确的结果 - 是做一个引用 SVG 过滤器的 CSS 过滤器。 SVG 滤镜中的 feColorMatrix 基元允许您直接选择颜色。

采用你的颜色 #424242 - 将每个 RGB 通道值除以 #FF 并将它们放在第五列,即颜色矩阵的前三行。在这种情况下,十六进制 #42 的十进制数为 68,因此将其除以 255(#FF 为十进制数),您将得到 0.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>

获得精确匹配的唯一方法是使用 SVG 颜色矩阵过滤器。

对于 RGB 颜色 #689d94,即 rgb(104, 157, 148),将每个原色的值​​除以 255:

将这些权重放入 SVG <filter> 矩阵 (前 3 行中的 5ᵗʰ 列):

<svg xmlns="http://www.w3.org/2000/svg">
  <defs>
    <filter id="689d94" color-interpolation-filters="sRGB">
      <feColorMatrix type="matrix" 
        values="0 0 0 0 0.40784 
                0 0 0 0 0.61569 
                0 0 0 0 0.58039 
                0 0 0 1 0"/>
    </filter>
  </defs>
</svg>

<filter>得有id(我用的是RGB十六进制码689d94),大家可以参考一下

如果 SVG 元素的 display 属性 设置为 none,并且有HTML 代码中的此 SVG 元素会不方便地占用一些 space,最好的方法是将此 SVG 转换为纯内联 CSS 过滤器。

要获得 内联过滤器 值,采用上面列出的 SVG 代码,通过删除换行符和不必要的 space 将其转换为单行,然后在前面加上url('data:image/svg+xml, 并将前面提到的 id 附加为 #689d94'):

div {
  background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="71.063" height="60.938"><path d="M33.938 0l-16.97 19.906H1.625L0 21.781v8.781l1.25 1.407h4.781l5.875 28.969h46.969l6.188-28.97h4.687l1.313-1.343v-8.844L69.5 19.906H54.656L37.312 0h-3.375zm1.593 7.594l9.594 12.312H26.25l9.281-12.312zm-20.281 16s-.405 2.9 1.594 3.844c1.998.942 4.406.03 4.406.03-1.666 2.763-3.638 3.551-5.469 2.688-3.312-1.562-.531-6.562-.531-6.562zm41.188.031s2.749 4.969-.563 6.531c-2.487 1.162-4.848-1.541-5.438-2.656 0 0 2.377.88 4.375-.063 1.999-.942 1.625-3.812 1.625-3.812z"/></svg>') no-repeat; // optimized from http://richard.parnaby-king.co.uk/basket.svg
  background-size: 100%;
  display: inline-block;
  height: 5em;
  width: 5em;
}
#colored {
  filter: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg"><defs><filter id="689d94" color-interpolation-filters="sRGB"><feColorMatrix type="matrix" values="0 0 0 0 0.40784 0 0 0 0 0.61569 0 0 0 0 0.58039 0 0 0 1 0"/></filter></defs></svg>#689d94');
  margin-left: 20px;
}
<!-- No <svg> in HTML; pure CSS -->
<div></div><div id="colored"></div>
<p style="background: #689d94">​</p>