feImage с внутренним источником

Цель

Я пытаюсь написать SVG-фильтр для визуализации волнового освещения поверх заданной формы. Итак, внутри этой формы я хочу, чтобы волны применялись, но я не хочу, чтобы за пределами этой формы был видимый эффект. Насколько я понимаю, я не могу использовать один и тот же источник изображения как для карты высот, используемой для волн, так и в качестве целевого домена для atop композиция. Поэтому я подумал, что для получения карты высот из отдельный объект с градиентной заливкой. Но пока мне не удалось сделать этот объект видимым внутри области эффекта фильтра.

Первая попытка

Код у меня есть до сих пор:

<?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, ресурс изображения отображается в соответствии с поведением 'изображение'; в противном случае указанный ресурс отображается в соответствии с поведением 'use' элемент. В любом случае текущая пользовательская система координат зависит от значения атрибута 'primitiveUnits' в элементе 'filter'.

Вторая попытка

use вместо image выглядит нормально, но я не уверен, как в этом случае определяется прямоугольная область. документация для use указывает, что в таком случае (упомянутый элемент не является ни элементом symbol, ни элементом svg), свойства width и height не имеют значения, но как это описывает прямоугольную область? Я также подумал, что, возможно, поможет смена примитивных единиц измерения. Или поместите изображение внутрь 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 моего фильтра?

растеризатор

Это изображение не предназначено для веб-развертывания, оно будет растрировано локально. Таким образом, совместимость с браузером не является большой проблемой; если вещь правильно отображается либо в Inkscape, либо в rsvg-convert, мне этого достаточно.


person MvG    schedule 06.11.2013    source источник


Ответы (1)


Есть много причин, по которым это может не сработать.

  1. Возможно, вам потребуется указать единицы измерения ширины и высоты svg (px, pt, em, % что угодно). IE не любит неуказанные размеры элемента SVG.
  2. Вы используете неправильный термин для ввода feComposite: «SourceImage» должно быть «SourceGraphic».
  3. Фильтры лучше применять непосредственно через свойство фильтра, а не через свойство стиля.
  4. Я не думаю, что вы можете ссылаться на символ непосредственно в feImage, вы должны сначала использовать его, а затем ссылаться на идентификатор элемента использования. (В любом случае, почему бы просто не использовать прямоугольник напрямую?)

Вот версия, которая работает в 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>
person Michael Mullany    schedule 07.11.2013
comment
Поддержка браузера для меня не так важна, растрирую локально. Но ни Inkscape, ни rsvg-convert не отображают ваше первое изображение так, как предполагалось. Они все глючат? Если это так, я, вероятно, должен подать отчеты об ошибках. Что касается symbol вместо простого rect: это была просто попытка, так как symbol с его viewBox больше походил на автономное изображение, а в документах говорилось, что feImage ведет себя почти так же, как use. Использование самого объекта для узора и feFill для раскрашивания в этом случае работает хорошо, но не получится, если базовый объект имеет несколько цветов или полупрозрачн в некоторых местах. - person MvG; 07.11.2013
comment
Если вы пытаетесь применить световые эффекты поверх частично прозрачного содержимого, вам придется обрабатывать освещение независимо. Я не знаю, почему inkscape задыхается от импорта feimage - извините. - person Michael Mullany; 07.11.2013