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

新手上路,请多包涵

我有一个白色图像用作 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>

原文由 Richard Parnaby-King 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 989
2 个回答

获得精确匹配的唯一方法是使用 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 元素,则某些浏览器(例如 Firefox)看不到/使用 SVG 过滤器不方便占用一些空间,最好的办法是将这个 SVG 转换成纯内联 CSS 滤镜。

要获取 内联过滤器 值,请采用上面列出的 SVG 代码,通过删除换行符和不必要的空格将其转换为单行,然后添加 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>

原文由 Ωmega 发布,翻译遵循 CC BY-SA 4.0 许可协议

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

如果您的图片是 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>

将基色转换为目标色

前两个步骤是静态的,每次我们需要找到目标调整时都会重复使用其结果( sepia 的实际值在 SVG Filters 规范 中定义)。

现在我们需要计算我们需要将什么应用到这个基色以获得目标颜色。首先将目标颜色(例如问题中给出的#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 树,而不是使用滤镜。过滤器在性能方面是昂贵的,特别是如果许多过滤器像这里一样被链接起来,并且它们还是页面的主要部分。所有浏览器都不支持它们。

原文由 user1693593 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题