feImage与内部来源

时间:2013-11-06 21:36:09

标签: svg svg-filters

目标

我正在尝试编写一个SVG滤镜来渲染顶部给定形状的波光照。所以在那个形状里面我希望波浪适用,但我希望在那个形状之外没有可见的效果。据我所知,我不能将相同的图像源用于用于波的高度图和atop composition的目标域。所以我认为可以使用<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>

相关文件

<feImage>州的文档:

  

如果‘xlink:href’引用独立的图像资源(如JPEG,PNG或SVG文件),则根据‘image’元素的行为呈现图像资源;否则,根据‘use’元素的行为呈现引用的资源。在任何一种情况下,当前用户坐标系都取决于‘primitiveUnits’元素上属性‘filter’的值。

第二次尝试

use代替image看起来对我来说没问题,但我不确定在这种情况下如何定义矩形区域。 documentation for use似乎表明在这种情况下(引用的元素既不是symbol也不是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>

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

核心问题

如何将SVG文件的片段用作光照的凹凸贴图,而不将其用作滤镜的SourceGraphic

光栅化

此图片不适用于Web部署,但会在本地进行栅格化。因此浏览器兼容性不是问题;如果事物在Inkscape或rsvg-convert下正确呈现,那对我来说已经足够了。

1 个答案:

答案 0 :(得分:2)

为什么这可能不起作用有很多原因。

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

    然而,这在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>
    

    并且(因为为什么不是)这里是一个添加镜面光照的例子:

    <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>