software-mansion / react-native-svg

SVG library for React Native, React Native Web, and plain React web projects.
MIT License
7.42k stars 1.12k forks source link

[15.4.0] SVG including filters don't render properly #2364

Open TomCorvus opened 1 month ago

TomCorvus commented 1 month ago

Description

Since 15.4.0 version, SVG including filters don't render properly.

Steps to reproduce

Install react-native-svg 15.4.0 Try to render this example:

import React, { memo, FC } from 'react'
import { SvgXml } from 'react-native-svg'

const xml = `<svg width="180" height="180" viewBox="0 0 180 180" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_di_1585_4261)">
<path d="M19 25.0226C19 20.5918 22.5918 17 27.0226 17H115.396C119.827 17 123.419 20.5918 123.419 25.0226V146.859C123.419 151.29 119.827 154.882 115.396 154.882H27.0226C22.5918 154.882 19 151.29 19 146.859V25.0226Z" fill="white"/>
</g>
<path d="M29.8062 119.21C29.8062 114.779 33.398 111.188 37.8287 111.188H104.681C109.112 111.188 112.704 114.779 112.704 119.21V131.806C112.704 136.237 109.112 139.829 104.681 139.829H37.8287C33.398 139.829 29.8062 136.237 29.8062 131.806V119.21Z" fill="#F6F7F8"/>
<path d="M29.8062 88.3205C29.8062 83.8898 33.398 80.2979 37.8287 80.2979H104.681C109.112 80.2979 112.704 83.8898 112.704 88.3205V95.6928C112.704 100.124 109.112 103.715 104.681 103.715H37.8287C33.398 103.715 29.8062 100.124 29.8062 95.6928V88.3205Z" fill="#F6F7F8"/>
<path d="M29.8062 58.9782C29.8062 54.5475 33.398 50.9556 37.8287 50.9556H104.681C109.112 50.9556 112.704 54.5475 112.704 58.9782V66.3505C112.704 70.7813 109.112 74.3731 104.681 74.3731H37.8287C33.398 74.3731 29.8062 70.7813 29.8062 66.3505V58.9782Z" fill="#F6F7F8"/>
<path d="M29.8064 38.5419C29.8064 34.958 32.7117 32.0528 36.2955 32.0528H59.3718C62.9556 32.0528 65.8609 34.958 65.8609 38.5419C65.8609 42.1257 62.9556 45.031 59.3718 45.031H36.2955C32.7117 45.031 29.8064 42.1257 29.8064 38.5419Z" fill="#F6F7F8"/>
<path d="M76.6489 38.5419C76.6489 34.9581 79.5542 32.0528 83.1381 32.0528H106.214C109.798 32.0528 112.703 34.9581 112.703 38.5419C112.703 42.1258 109.798 45.0311 106.214 45.0311H83.1381C79.5542 45.0311 76.6489 42.1258 76.6489 38.5419Z" fill="#F6F7F8"/>
<g opacity="0.98" filter="url(#filter1_ii_1585_4261)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M119.692 126.656C119.041 127.002 118.374 127.33 117.693 127.639C100.257 135.544 79.8361 128.09 72.0825 110.989C64.329 93.8877 72.1784 73.6158 89.6148 65.7101C107.051 57.8045 127.472 65.2589 135.225 82.36C140.55 94.1046 138.516 107.345 131.071 117.048C134.769 121.265 152.44 138.712 157.771 143.126C158.189 143.471 158.274 144.075 157.946 144.505C155.008 148.355 149.814 153.167 146.125 154.606C145.639 154.796 145.091 154.533 144.797 154.102C142.185 150.27 129.353 136.181 119.692 126.656ZM124.805 87.085C129.999 98.5409 124.741 112.121 113.06 117.417C101.38 122.713 87.7002 117.719 82.5061 106.263C77.3121 94.8073 82.5704 81.2273 94.2509 75.9313C105.931 70.6354 119.611 75.6291 124.805 87.085Z" fill="#1656FF"/>
</g>
<ellipse cx="151.48" cy="148.756" rx="8.42697" ry="2.42153" transform="rotate(-41.0941 151.48 148.756)" fill="#0745EB"/>
<g opacity="0.64" filter="url(#filter2_i_1585_4261)">
<ellipse cx="103.657" cy="96.6735" rx="23.2218" ry="22.7752" transform="rotate(-24.3894 103.657 96.6735)" fill="url(#paint0_linear_1585_4261)"/>
</g>
<mask id="mask0_1585_4261" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="80" y="73" width="47" height="47">
<ellipse cx="103.656" cy="96.6733" rx="23.2218" ry="22.7752" transform="rotate(-24.3894 103.656 96.6733)" fill="#B7B8B9"/>
</mask>
<g mask="url(#mask0_1585_4261)">
<g opacity="0.64" filter="url(#filter3_f_1585_4261)">
<path d="M92.483 82.7245L83.7667 83.977C83.6543 83.9931 83.5579 84.0376 83.4838 84.1237C80.5126 87.5761 72.2233 108.018 94.1309 118.162C94.5434 118.353 94.9706 117.949 94.7745 117.539C92.1686 112.09 85.3122 98.1045 93 83.479C93.1933 83.1114 92.8941 82.6654 92.483 82.7245Z" fill="white"/>
</g>
<g opacity="0.64" filter="url(#filter4_f_1585_4261)">
<path d="M122.089 86.1098L124.774 84.8135C135.282 96.2926 124.387 112.809 115.675 116.023C120.504 113.956 128.571 99.5333 122.089 86.1098Z" fill="white"/>
</g>
</g>
<g opacity="0.98" filter="url(#filter5_i_1585_4261)">
<path d="M124.442 87.2496C129.542 98.4977 124.382 111.844 112.896 117.052C101.41 122.26 87.9712 117.346 82.8713 106.097C77.7715 94.8494 82.9309 81.5028 94.417 76.2951C105.903 71.0873 119.342 76.0015 124.442 87.2496Z" stroke="#0745EB" stroke-width="0.8"/>
</g>
<g opacity="0.5" filter="url(#filter6_f_1585_4261)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M102.827 64.6869C86.3157 65.2557 73.0987 79.359 73.0987 96.6737C73.0987 113.988 86.3157 128.092 102.827 128.66C102.482 128.672 102.137 128.678 101.79 128.678C84.7989 128.678 71.0251 114.349 71.0251 96.6737C71.0251 78.998 84.7989 64.6691 101.79 64.6691C102.137 64.6691 102.482 64.675 102.827 64.6869Z" fill="url(#paint1_linear_1585_4261)"/>
</g>
<g opacity="0.5" filter="url(#filter7_f_1585_4261)">
<path d="M130.904 120.209L152.482 141.886" stroke="white" stroke-linecap="round"/>
</g>
<defs>
<filter id="filter0_di_1585_4261" x="11" y="11" width="120.419" height="153.882" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="2"/>
<feGaussianBlur stdDeviation="4"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.06 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1585_4261"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_1585_4261" result="shape"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="-2"/>
<feGaussianBlur stdDeviation="1"/>
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.2 0 0 0 0 0.2 0 0 0 0 0.2 0 0 0 0.08 0"/>
<feBlend mode="normal" in2="shape" result="effect2_innerShadow_1585_4261"/>
</filter>
<filter id="filter1_ii_1585_4261" x="69.0931" y="61.5533" width="91.0535" height="95.1153" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dx="2" dy="2"/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.32549 0 0 0 0 0.509804 0 0 0 0 1 0 0 0 1 0"/>
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_1585_4261"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="-1"/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0.254902 0 0 0 0 0.929412 0 0 0 1 0"/>
<feBlend mode="normal" in2="effect1_innerShadow_1585_4261" result="effect2_innerShadow_1585_4261"/>
</filter>
<filter id="filter2_i_1585_4261" x="80.5045" y="72.816" width="46.3041" height="46.715" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="-1"/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.513726 0 0 0 0 0.513726 0 0 0 0 0.517647 0 0 0 0.5 0"/>
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_1585_4261"/>
</filter>
<filter id="filter3_f_1585_4261" x="78.4564" y="81.7192" width="17.3672" height="37.4914" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.5" result="effect1_foregroundBlur_1585_4261"/>
</filter>
<filter id="filter4_f_1585_4261" x="114.676" y="83.8135" width="15.416" height="33.209" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.5" result="effect1_foregroundBlur_1585_4261"/>
</filter>
<filter id="filter5_i_1585_4261" x="80.5045" y="73.816" width="46.3041" height="45.715" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="4"/>
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.0416667 0 0 0 0 0.253034 0 0 0 0 0.833333 0 0 0 1 0"/>
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_1585_4261"/>
</filter>
<filter id="filter6_f_1585_4261" x="70.0251" y="63.6691" width="33.8014" height="66.0092" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="0.5" result="effect1_foregroundBlur_1585_4261"/>
</filter>
<filter id="filter7_f_1585_4261" x="128.404" y="117.709" width="26.5776" height="26.6769" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="1" result="effect1_foregroundBlur_1585_4261"/>
</filter>
<linearGradient id="paint0_linear_1585_4261" x1="105.239" y1="80.9134" x2="96.1144" y2="118.129" gradientUnits="userSpaceOnUse">
<stop stop-color="#DADCDF"/>
<stop offset="1" stop-color="#F1F2F4"/>
</linearGradient>
<linearGradient id="paint1_linear_1585_4261" x1="68.8038" y1="96.6737" x2="98.4855" y2="95.1383" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
</defs>
</svg>
`

export const NoDataIcon: FC = () => (
    <SvgXml xml={xml} width='180' height='180' />
)

export default memo(NoDataIcon)

I saw this thread and this PR: https://github.com/software-mansion/react-native-svg/issues/2356 https://github.com/software-mansion/react-native-svg/pull/2360

But it only talks about IOS while the problem seems to also be present on Android.

Vanilla iOS Android
vanilla-svg ios-svg android-svg

Downgrade to 15.3.0 fix this problem.

Snack or a link to a repository

https://github.com/fikkatra/react-native-svg-with-filters

SVG version

15.4.0

React Native version

0.73.1

Platforms

Android, iOS

JavaScript runtime

Hermes

Workflow

React Native

Architecture

Paper (Old Architecture)

Build type

Debug app & production bundle

Device

Real device

Device model

All devices (Emulators/Real)

Acknowledgements

Yes

github-actions[bot] commented 1 month ago

Hey! 👋

The issue doesn't seem to contain a minimal reproduction.

Could you provide a snack or a link to a GitHub repository under your username that reproduces the problem?

bohdanprog commented 1 month ago

Hello, @TomCorvus. Thanks for letting us know about that problem. @jakex7 maybe you could take a look at it? Thank you

jakex7 commented 1 month ago

Hi @TomCorvus, there are a few issues here, so let's break them down:

  1. Since not all filters are implemented yet (#2362), filters other than FeColorMatrix have been removed.
  2. There was a bug on Android (#2365) causing incorrect color shifts when using FeColorMatrix.
  3. On iOS, applying more than one FeColorMatrix resulted in incorrect outcomes. This has been fixed (#2366).
  4. Currently, we lack support for presentation attributes on the Filter element, particularly the color-interpolation-filters property. This means we can't control which color interpolation is used when applying filters. From my tests, it appears that iOS uses linearRGB, while Android uses sRGB.

In the next version (15.5.0) we will release the above fixes and your SVG should render much better, while there will still be a subtle difference due to point 4. If there is anything else I can help you with, feel free to ping me here.

TomCorvus commented 1 month ago

Thank you @jakex7 I'm waiting the next version to check all of that.

TomCorvus commented 1 month ago

@jakex7 Here the results with 15.5.0 version of react-native-svg

Vanilla iOS Android
File File (1) share_6224208875100170245

Better than before but not perfect. Just to understand: on 15.3.0 version, this kind of SVG was render properly, why the render changes so radically on newest version? In other words, why change something that works? The vanilla render above is on iOS and the new render is blurred and colors are wrong.

Thanks for your help, and your works btw.

jakex7 commented 1 month ago

@TomCorvus I apologize for any inconvenience caused by the introduction of filters. Since not all filters are implemented yet, the other filters are being removed, resulting in something like this:

<filter id="filter0_di_1585_4261">
//  <feFlood flood-opacity="0" result="BackgroundImageFix"/>
    <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
    <feOffset dy="2"/>
    <feGaussianBlur stdDeviation="4"/>
//  <feComposite in2="hardAlpha" operator="out"/>
    <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.06 0"/>
//  <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1585_4261"/>
//  <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_1585_4261" result="shape"/>
    <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
    <feOffset dy="-2"/>
    <feGaussianBlur stdDeviation="1"/>
//  <feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
    <feColorMatrix type="matrix" values="0 0 0 0 0.2 0 0 0 0 0.2 0 0 0 0 0.2 0 0 0 0.08 0"/>
//  <feBlend mode="normal" in2="shape" result="effect2_innerShadow_1585_4261"/>
</filter>

As you can see, there is no FeBlend. Instead, the output from FeGaussianBlur is used as the input for FeColorMatrix, which is the last filter function, producing the final image. That's why your results are blurred on the new version.

If you want to achieve the results from version 15.3.0, then you can remove the <filter> tags from your SVG code or remove the filter prop from elements.

TomCorvus commented 1 month ago

Don't be sorry about that, It just a way for me to understand the work behind all of this. I'll wait the whole filters implementation and it will be awesome. Thanks for the explanation.