【问题标题】:SVG - mask feGaussianBlur with radialGradientSVG - 带有radialGradient的掩码feGaussianBlur
【发布时间】:2021-12-26 06:41:21
【问题描述】:

我想模糊图像的角落,同时保留清晰的中心。 使用 css background-blur() 是没有问题的,因为 Firefox 不支持它。 在模糊的图像上添加清晰的图像,然后将第一个图像遮住也是不可行的,因为最后我想用 three.js 场景更改静态图像。

我尝试跟随this tutorial,但使用的是径向渐变,而不是固定条。

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
      <defs>
        <filter id="blurlayer" width="100%" height="100%">
            
          <feGaussianBlur stdDeviation="4" result="blur"/>
            
          <radialGradient id="radialGradient" cx="50%" cy="50%" r="50%" fx="50%" fy="50%" result="mask">
            <stop offset="0%" stop-color="white" stop-opacity="1" />
            <stop offset="100%" stop-color="black" stop-opacity="0" />
          </radialGradient>
            
          <feComposite in="blur" in2="mask" operator="in" result="comp" />
            
          <feMerge result="merge">
            <feMergeNode in="SourceGraphic" />
            <feMergeNode in="comp" />
          </feMerge> 
        </filter>
      </defs>

      <image filter="url(#blurlayer)" x="0" y="0" width="100%" height="100%"   xlink:href="https://www.wildtextures.com/wp-content/uploads/wildtextures-grey-felt-texture.jpg"/>
    </svg>

它不起作用。有人可以帮我找出原因吗? 我设置了一个codepen,如果这对任何人有帮助的话。

编辑: 虽然答案有效,但既然我已经实现了它,我想警告其他所有人:在 Firefox 上,这会减慢我的 Three.js 场景的爬行速度(不过,我测试的所有其他浏览器似乎都很好)。

【问题讨论】:

  • 对不起,我措辞错误,我的意思是“背景模糊()”。不过,CanIuse.com 向我证实了这一点。不幸的是我不能使用 blur(),因为我不能直接定位到 three.js 画布。

标签: svg svg-filters


【解决方案1】:

您必须做更多的工作-您不能在过滤器中间放置radialGradient-过滤器内只允许使用过滤器基元,并且您需要导入要使用的任何图像/形状feImage。

此外,当通过 feComposite/in 进行遮罩时,“in”运算符仅使用 Alpha 通道(与使用亮度的实际遮罩不同),因此您可以使用具有可变不透明度的黑色/黑色渐变。

最后,因为 Firefox 不支持 feImage 中的片段标识符,如果你想要 FF 支持,你必须在内容中定义你的掩码并通过 feImage 导入你想要使用的图像。这使得过滤器不可重复使用,但如果这是一次关闭的内容,那很好。如果您确实想更普遍地使用此过滤器,那么您可以定义一个渐变填充的矩形,然后将其转换为完整的 SVG 图像,然后通过 feImage 中的 data:uri 内联该图像。这是更多的工作(而且我似乎总是把 svg+xml 数据 URI 的转义规则弄错了)——所以我没有在这里做。

FWIW - 该教程既完整又正确。

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
      <defs>
        
        <radialGradient id="radialGradient" cx="50%" cy="50%" r="50%" fx="50%" fy="50%" result="mask">
            <stop offset="0%" stop-color="black" stop-opacity="1" />
            <stop offset="100%" stop-color="black" stop-opacity="0" />
        </radialGradient>
            
        
        <filter id="blurlayer" x="0%" y="0%" width="100%" height="100%">
          <feImage xlink:href="https://www.wildtextures.com/wp-content/uploads/wildtextures-grey-felt-texture.jpg" width="100%" height="100%" result="original-image" preserveAspectRatio="none"/>         
          <feComposite in="original-image" in2="SourceGraphic" operator="in" result="unblurred" />  
          
     <feGaussianBlur in="original-image" stdDeviation="4" result="blurred-image"/>
          <feComponentTransfer in="SourceGraphic" result="invertlight">
                <feFuncA type="table" tableValues="1 0"/>
          </feComponentTransfer>
          <feComposite in="blurred-image" operator="in"/>
          
          <feComposite operator="over" in="unblurred"/>
        </filter>
      </defs>
  
<g filter="url(#blurlayer)">
      <rect fill="url(#radialGradient)" x="0" y="0" width="100%" height="100%"/>
</g>
    </svg>

更新:这是 data:uri 版本的样子: (请注意,我必须稍微扩大过滤内容的大小,以便过滤器会剪掉由反转导致的边缘伪影)。

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="100%">
      <defs>        
        <filter id="blurlayer" x="0%" y="0%" width="100%" height="100%">
          <feImage xlink:href='data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2ZXJzaW9uPSIxLjEiIHg9IjAiIHk9IjAiIHZpZXdCb3g9IjAgMCAxMDAgMTAwIiBoZWlnaHQ9IjEwMCUiIHdpZHRoPSIxMDAlIj48ZGVmcz4gICAgICAgIDxyYWRpYWxHcmFkaWVudCBpZD0ibXlHcmFkaWVudCIgY3g9IjUwJSIgY3k9IjUwJSIgcj0iNTAlIiBmeD0iNTAlIiBmeT0iNTAlIiByZXN1bHQ9Im1hc2siPjxzdG9wIG9mZnNldD0iMCUiIHN0b3AtY29sb3I9ImJsYWNrIiBzdG9wLW9wYWNpdHk9IjEiIC8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSJibGFjayIgc3RvcC1vcGFjaXR5PSIwIi8+CjwvcmFkaWFsR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAlIiB5PSIwJSIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0idXJsKCNteUdyYWRpZW50KSIvPjwvc3ZnPg==' width="100%" height="100%" result="blur-mask" preserveAspectRatio="none"/>
      <feComposite in2="blur-mask" in="SourceGraphic" operator="in" result="unblurred" /> 
     <feGaussianBlur in="SourceGraphic" stdDeviation="4" result="blurred-image"/>
          <feComponentTransfer in="blur-mask" result="invertlight">
             <feFuncA type="table" tableValues="1 0"/>
          </feComponentTransfer>
          <feComposite in="blurred-image" operator="in"/>
          <feComposite operator="over" in="unblurred"/>
      </filter>
</defs>
  
  <g filter="url(#blurlayer)">
      <image xlink:href="https://www.wildtextures.com/wp-content/uploads/wildtextures-grey-felt-texture.jpg" x="-5%" y="-5%" width="110%" height="110%" preserveAspectRatio="none"/> 
</g>
    </svg>

data:uri 是这个 SVG 的 base64 编码版本。

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" x="0" y="0" viewBox="0 0 100 100" height="100%" width="100%"><defs><radialGradient id="myGradient" cx="50%" cy="50%" r="50%" fx="50%" fy="50%" result="mask"><stop offset="0%" stop-color="black" stop-opacity="1" /><stop offset="100%" stop-color="black" stop-opacity="0"/>
</radialGradient></defs><rect x="0%" y="0%" width="100%" height="100%" fill="url(#myGradient)"/></svg>

【讨论】:

  • 非常感谢您的简洁描述!我最初的问题解决了。我可以再麻烦你一点,请你帮我实现一个 feImage 的 three.js 场景吗? (这甚至可能吗?)我尝试在这里遵循本教程:developer.mozilla.org/en-US/docs/Web/SVG/… 但我无法让它工作。可能我只是个白痴...我设置了一个代码框,如果有帮助:codesandbox.io/s/vue-svg-filter-forked-2759d?file=/src/App.vue
  • 如果你需要对场景应用滤镜,那么你不能使用这个答案,你必须使用我最后提到的feImage数据:uri版本(如果你想要FF支持) .
  • 我越是试图了解我需要改变什么,我就越感到困惑。你能详细说明最后一部分吗?我不是专业的网页设计师,所以我不确定你的意思......谢谢!
  • 我添加了一个示例,显示 data:uri 的样子。
  • @MichaelMullany 很好的答案,但不幸的是,我最多只能投一个赞成票。我希望其他人会欣赏你的精彩回答。