SVG - маска с фильтром feGaussianBlur радиальным градиентом
Я хочу размыть углы изображения, сохранив резкий центр. Использование css backdrop-blur() исключено, потому что Firefox его не поддерживает. Добавление резкого изображения поверх размытого и затем маскирование первого также неосуществимо, так как в конце я хочу изменить статическое изображение с помощью сцены three.js.
Я попытался следовать этому руководству, но с радиальным градиентом, а не с фиксированной полосой.
<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, если это кому-то поможет.
Свободный перевод вопроса SVG - mask feGaussianBlur with radialGradient от участника @morph3us.
Ответы (1 шт):
Вам нужно проделать немного больше работы - вы не можете поместить radialGradient в середину фильтра - внутри фильтра разрешены только примитивы фильтра, и вам нужно импортировать любое изображение / фигуру, которую вы хотите использовать, через feImage.
Кроме того, при маскировании с помощью feComposite / in - оператор «in» использует только альфа-канал (в отличие от реальных масок, использующих яркость), поэтому вы можете использовать черный / черный градиент с переменной непрозрачностью.
Наконец, поскольку Firefox не поддерживает идентификаторы фрагментов внутри feImage, поэтому если вам нужна поддержка Firefox, вы должны определить свою маску в содержимом и импортировать изображение, которое вы хотите использовать, через feImage.
Это делает фильтр не пригодным для повторного использования, но если это один раз, это нормально.
Если вы действительно хотите использовать этот фильтр в более общем плане, вы можете определить прямоугольник с градиентной заливкой, а затем преобразовать его в полное изображение SVG, которое вы затем встроите через data: uri внутри feImage.
Это больше работы (и мне всегда кажется, что правила экранирования для svg + xml data 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>
Примечание переводчика:
FWIW одна из самых вежливых текстовых аббревиатур, которая расшифровывается, как «не знаю, насколько это важно
Речь идёт о ссылке на руководство, указанной в вопросе
Update
Вот как будет выглядеть версия 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>
Свободный перевод Ответа от участника @Michael Mullany.
Данные: 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>

