feImage 与内部来源

MvG*_*MvG 7 svg svg-filters

目标

我正在尝试编写一个 SVG 过滤器来给定的形状呈现波浪照明。所以在那个形状里面我想要波浪应用,但我不希望在那个形状之外没有可见的效果。据我所知,我不能将相同的图像源用于波浪的高度图和atop组合的目标域。所以我认为一个<feImage>元素可能用于从单独的渐变填充对象获取高度图。但到目前为止,我还没有成功地使该对象在滤镜效果区域内可见。

第一次尝试

我到目前为止的代码:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg version="1.1" width="512" height="512"
     xmlns="http://www.w3.org/2000/svg"
     xmlns:xlink="http://www.w3.org/1999/xlink">
  <defs>
    <radialGradient id="waveFill" r="5%" spreadMethod="reflect">
      <stop offset="0%" stop-opacity="1.00"/>
      <stop offset="20%" stop-opacity="0.90"/>
      <stop offset="40%" stop-opacity="0.65"/>
      <stop offset="60%" stop-opacity="0.35"/>
      <stop offset="80%" stop-opacity="0.10"/>
      <stop offset="100%" stop-opacity="0.00"/>
    </radialGradient>
    <rect id="waveImg" x="-210" y="-105" width="420" height="210"
          stroke="none" fill="url(#waveFill)"/>
    <filter id="waveFilter">
      <feImage xlink:href="#waveImg" result="waves"/>
      <!-- feSpecularLighting and so on will be added later on -->
      <feComposite operator="atop" in="waves" in2="SourceImage"/>
    </filter>
  </defs>
  <g transform="translate(256 256)">
    <!-- use xlink:href="#waveImg"/ works -->
    <ellipse rx="200" ry="100" fill="#0000ff" stroke="none"
             style="filter:url(#waveFilter)"/>
  </g>
</svg>
Run Code Online (Sandbox Code Playgroud)

相关文件

<feImage>状态的文档:

如果'xlink:href'引用了一个独立的图像资源,例如 JPEG、PNG 或 SVG 文件,那么图像资源将根据'image'元素的行为进行渲染;否则,根据“use”元素的行为呈现引用的资源。在任何一种情况下,当前用户坐标系都取决于“filter”元素上的primitiveUnits”属性值。

第二次尝试

use而不是image对我来说看起来不错,但我不确定在这种情况下如何定义矩形区域。的文档use似乎表明,在这种情况下(引用的元素既不是 asymbol也不是svg元素),widthheight属性无关紧要,但这如何描述矩形区域?我还认为,也许改变原始单位会有所帮助。或者在symbol. 所以我的第二次尝试是以下一次:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg version="1.1" width="512" height="512"
     xmlns="http://www.w3.org/2000/svg"
     xmlns:xlink="http://www.w3.org/1999/xlink">
  <defs>
    <radialGradient id="waveFill" r="5%" spreadMethod="reflect">
      <stop offset="0%" stop-opacity="1.00"/>
      <stop offset="20%" stop-opacity="0.90"/>
      <stop offset="40%" stop-opacity="0.65"/>
      <stop offset="60%" stop-opacity="0.35"/>
      <stop offset="80%" stop-opacity="0.10"/>
      <stop offset="100%" stop-opacity="0.00"/>
    </radialGradient>
    <symbol viewBox="0 0 100 100" id="waveImg" preserveAspectRatio="none">
      <rect width="100" height="100" stroke="none" fill="url(#waveFill)"/>
    </symbol>
    <filter id="waveFilter" primitiveUnits="objectBoundingBox">
      <feImage xlink:href="#waveImg" x="0" y="0" width="100%" height="100%"
               preserveAspectRatio="none" result="waves"/>
      <!-- feSpecularLighting and so on will be added later on -->
      <feComposite operator="atop" in="waves" in2="SourceImage"/>
    </filter>
  </defs>
  <g transform="translate(256 256)">
    <!-- use xlink:href="#waveImg"/ works -->
    <ellipse rx="200" ry="100" fill="#0000ff" stroke="none"
             style="filter:url(#waveFilter)"/>
    <ellipse rx="200" ry="100" fill="none" stroke="#ff0000"/>
  </g>
</svg>
Run Code Online (Sandbox Code Playgroud)

仍然没有图像可见。我究竟做错了什么?

核心问题

如何将我的 SVG 文件片段用作照明的凹凸贴图,而不将其用作SourceGraphic我的过滤器?

光栅化器

此图像不适用于 Web 部署,但会在本地进行光栅化。所以浏览器兼容性不是什么大问题;如果这件事在 Inkscape 或 rsvg-convert 下正确呈现,那对我来说就足够了。

Mic*_*any 6

这可能行不通的原因有很多。

  1. 您可能需要指定 svg 宽度和高度的单位(px、pt、em、% 等)。IE 不喜欢未指定的 SVG 元素尺寸。
  2. 您对 feComposite 输入使用了错误的术语:“SourceImage”应该是“SourceGraphic”。
  3. 过滤器最好直接通过过滤器属性应用,而不是通过样式属性。
  4. 我认为您不能直接在 feImage 中引用符号,您必须先 <use 它,然后引用 use 元素上的 id。(无论如何,为什么不直接使用 rect 呢?)

这是一个使用您的方法在 Chrome(可能还有 Safari)中运行的版本。

<svg version="1.1" width="512px" height="512px" viewbox="0 0 512 512"
     xmlns="http://www.w3.org/2000/svg"
     xmlns:xlink="http://www.w3.org/1999/xlink">   <defs>
    <radialGradient id="waveFill" r="5%" spreadMethod="reflect">
      <stop offset="0%" stop-opacity="1.00"/>
      <stop offset="20%" stop-opacity="0.90"/>
      <stop offset="40%" stop-opacity="0.65"/>
      <stop offset="60%" stop-opacity="0.35"/>
      <stop offset="80%" stop-opacity="0.10"/>
      <stop offset="100%" stop-opacity="0.00"/>
    </radialGradient>

      <rect id="waveImg" width="100%" height="100%" stroke="none" fill="url(#waveFill)"/>

    <filter id="waveFilter" primitiveUnits="objectBoundingBox">
      <feImage xlink:href="#waveImg" x="0%" y="0%" width="100%" height="100%" result="waves"/>
      <!-- feSpecularLighting and so on will be added later on -->
      <feComposite operator="atop" in="waves" in2="SourceGraphic"/>
    </filter>   
     </defs>  
     <g transform="translate(256 256)">


    <ellipse rx="200" ry="100" fill="#0000ff" stroke="none"
             filter="url(#waveFilter)"/>
    <ellipse rx="200" ry="100" fill="none" stroke="#ff0000"/>   </g> </svg>
Run Code Online (Sandbox Code Playgroud)

然而,这在 Firefox 中不起作用,因为不支持 feImage 的对象输入,并且根据我的测试,feImage 单元在 IE 中存在相当多的错误。

您没有理由不能重复使用源图形来实现灯光效果 - 这是您尝试执行的操作的较短版本,它可以跨浏览器工作并避免 feImage。

<svg version="1.1" x="0px" y="0px" width="512px" height="512px" viewbox="0 0 512 512"
     xmlns="http://www.w3.org/2000/svg"
     xmlns:xlink="http://www.w3.org/1999/xlink">   <defs>
    <radialGradient id="waveFill" r="5%" spreadMethod="reflect">
      <stop offset="0%" stop-opacity="1.00"/>
      <stop offset="20%" stop-opacity="0.90"/>
      <stop offset="40%" stop-opacity="0.65"/>
      <stop offset="60%" stop-opacity="0.35"/>
      <stop offset="80%" stop-opacity="0.10"/>
      <stop offset="100%" stop-opacity="0.00"/>
    </radialGradient>

    <filter id="waveFilter" x="0%" y="0%" width="100%" height="100%">
      <feFlood flood-color="#0000ff" result="blue"/>
      <feComposite operator="in" in2="SourceGraphic" in="blue"/>
    </filter>  
    </defs> 
    <g transform="translate(256 256)">
    <!-- use xlink:href="#waveImg"/ works -->
    <ellipse rx="200" ry="100" fill="url(#waveFill)" filter="url(#waveFilter)"/>
    <ellipse rx="200" ry="100" fill="none" stroke="#ff0000"/>   </g> </svg>
Run Code Online (Sandbox Code Playgroud)

并且(因为为什么不)这是一个添加了镜面照明的示例:

<svg version="1.1" x="0px" y="0px" width="512px" height="512px" viewbox="0 0 512 512"
     xmlns="http://www.w3.org/2000/svg"
     xmlns:xlink="http://www.w3.org/1999/xlink">
  <defs>
    <radialGradient id="waveFill" r="5%" spreadMethod="reflect">
      <stop offset="0%" stop-opacity="1.00"/>
      <stop offset="20%" stop-opacity="0.90"/>
      <stop offset="40%" stop-opacity="0.65"/>
      <stop offset="60%" stop-opacity="0.35"/>
      <stop offset="80%" stop-opacity="0.10"/>
      <stop offset="100%" stop-opacity="0.00"/>
    </radialGradient>

    <filter id="waveFilter" x="0%" y="0%" width="100%" height="100%">
      <feFlood flood-color="#0000ff" result="blue"/>
      <feComposite operator="in" in2="SourceGraphic" in="blue"                 
          result="sourcewithblue"/>

      <feSpecularLighting in="SourceAlpha" result="specOut" 
         specularConstant="2" specularExponent="20" lighting-color="white" 
         surfaceScale="2">
        <fePointLight  x="-200" y="-200" z="200"/> 
      </feSpecularLighting>

      <feComposite operator="arithmetic" in="specOut" in2="sourcewithblue" k1="0" k2="1" k3="1" result="unclippedoutput"/>
      <feComposite operator="in" in="unclippedoutput" in2="SourceGraphic"/>

    </filter>
  </defs>
 <g transform="translate(256 256)">
<ellipse rx="200" ry="100" fill="url(#waveFill)" filter="url(#waveFilter)"/>
<ellipse rx="200" ry="100" fill="none" stroke="#ff0000"/>
</g>
</svg>
Run Code Online (Sandbox Code Playgroud)