【问题标题】:Replace one color using SVG filters使用 SVG 过滤器替换一种颜色
【发布时间】:2021-05-10 14:02:49
【问题描述】:

是否可以拍摄一张 IMG 图片并将一种确切的颜色替换为另一种颜色,例如将 #fff 替换为 #000,同时保持所有其他颜色不变?可能来自 SVG 过滤器的颜色矩阵会有所帮助?

【问题讨论】:

    标签: canvas svg svg-filters


    【解决方案1】:

    这对于 Canvas 来说是微不足道的。也可以使用 SVG,但它很复杂。以下方法适用于传统的完全不透明图像。首先,您使用长 ComponentTransfer 将每个通道中的每个不匹配颜色值转换为零,并将每个匹配颜色值转换为 1(256 个成员 tableValues 数组中唯一“1”的索引应该与您的 r、g 和 b 匹配替换值)。然后,您使用颜色矩阵将除生成的白色像素之外的所有内容的 alpha 清零。您将结果用作具有目标颜色的 feFlood 的蒙版,并将结果合成到原始图形的顶部。例如,以下代码将特定颜色 - rgb(87, 78, 29) - 替换为蓝色。

    <svg width="600px" height="600px" viewBox="0 0 600 600">
      <defs>
        <filter id="color-replace" color-interpolation-filters="sRGB">
          <!-- Replace rgb(87,78,29) with blue. -->
          <feComponentTransfer >
            <feFuncR type="discrete" tableValues="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"/>
            <feFuncG type="discrete" tableValues="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"/>
            <feFuncB type="discrete" tableValues="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"/>
          </feComponentTransfer>
    
          <feColorMatrix type="matrix" values="1 0 0 0 0
                                               0 1 0 0 0
                                               0 0 1 0 0
                                               1 1 1 1 -3" result="selectedColor"/>
    
          <feFlood flood-color="blue"/>
          <feComposite operator="in" in2="selectedColor"/>
          <feComposite operator="over" in2="SourceGraphic"/>
        </filter>
      </defs>
      <g filter="url(#color-replace)">
        <rect  x="50" y="50" height="100" width="100" fill="rgb(86,77,28)"/>
        <rect  x="250" y="50" height="100" width="100" fill="rgb(86,77,29)"/>
        <rect  x="450" y="50" height="100" width="100" fill="rgb(86,78,29)"/>
        <rect  x="50" y="250" height="100" width="100" fill="rgb(87,77,29)"/>
        <rect  x="250" y="250" height="100" width="100" fill="rgb(87,78,29)"/>
        <rect  x="450" y="250" height="100" width="100" fill="rgb(87,78,30)"/>
        <rect  x="50" y="450" height="100" width="100" fill="rgb(88,78,30)"/>
        <rect  x="250" y="450" height="100" width="100" fill="rgb(88,79,29)"/>
        <rect  x="450" y="450" height="100" width="100" fill="rgb(88,79,30)"/>
      </g>
    </svg>

    更新:

    如果您想用不透明度小于 1 的颜色替换原始颜色,那么您需要采取额外的步骤 - 并在替换之前移除所选颜色。您可以通过这种方式扩展过滤器来完成此操作。

      <--snipping first half of filter -->
    
      <feColorMatrix type="matrix" values="1 0 0 0 0
                                           0 1 0 0 0
                                           0 0 1 0 0
                                           1 1 1 1 -3" result="selectedColor"/>
    
      <feComposite operator="out" in="SourceGraphic" result="notSelectedColor"/>
      <feFlood flood-color="blue" flood-opacity="0.5"/>
      <feComposite operator="in" in2="selectedColor"/>
      <feComposite operator="over" in2="notSelectedColor"/>
    </filter>
    

    【讨论】:

    • 我只是使用此代码的变体来替换 iframe 中的背景颜色。谢谢!
    • 这非常有效,但如果您还希望目标颜色具有不同的 alpha,例如 0.5,该怎么办? flood-color="blue" flood-opacity="0.5" 似乎不起作用,在 &lt;feFuncA/&gt; 的 tableValues 中设置 128“0”和 128“1”也不起作用。
    • 添加了一个更新,允许您将替换颜色变为可变不透明度。
    • 这种方法不适用于 Chrome(在 77 中测试),或者确切地说不适用于任何基于 webkit 的浏览器。只有 Firefox 处理得当。问题似乎出在feComponentTransfer 上,其中tableValues 被Chrome 以一种相当奇怪的方式解释。
    • 这仍然适用于我的 Chrome 77/Win10。有几个 Chrome GPU 标志会阻止过滤器 - 也许你设置了其中一个?
    猜你喜欢
    • 2023-01-27
    • 2014-05-07
    • 2019-07-06
    • 2015-03-15
    • 2013-06-09
    • 2015-03-21
    • 2015-12-19
    • 2015-02-12
    相关资源
    最近更新 更多