fix: applying multiple filters on iOS (#2366)

# Summary

Applying multiple `FeColorFilter` instances can cause unexpected
behavior on iOS, likely due to a bug in `CoreImage` where the `CIImage`
recipe isn't applied step by step as it should be. This fix ensures that
the filter result is rendered after each application by converting the
image to `CGImage` and then back to `CIImage`.

## Test Plan

With this simple test, we can prove that these changes are working
```tsx
<Svg height="200" width="200">
  <Filter id="filter">
    <FeColorMatrix type="matrix" values="78 -70 -7 0 0 -21 29 -7 0 0 -21 -70 0 0 0 0 0 0 1 0"/>
    <FeColorMatrix type="matrix" values="0.2126, 0.7152, 0.0722, 0, 0, 0.2126, 0.7152, 0.0722, 0, 0, 0.2126, 0.7152, 0, 0, 0, 0, 0, 0, 1, 0"/>
  </Filter>
  <Rect width="200" height="200" fill="red" filter="url(#filter)"/>
</Svg>
```

| Web | iOS before changes | iOS after changes |
| --- | --- | --- |
| <img width="242" alt="image"
src="https://github.com/user-attachments/assets/dc683341-b3ca-4fab-86d8-cf72b15c13d4">
| <img width="237" alt="image"
src="https://github.com/user-attachments/assets/d4a1af5d-ae67-4ed9-9dbd-d03540b2c63c">
| <img width="249" alt="image"
src="https://github.com/user-attachments/assets/83e856a6-5bcc-4534-ad7b-a1f188434e1c">
|
This commit is contained in:
Jakub Grzywacz
2024-07-25 10:15:08 +02:00
committed by GitHub
parent 9a2cd3d855
commit 00e492e8cf
3 changed files with 37 additions and 1 deletions
+6 -1
View File
@@ -1,5 +1,6 @@
#import "RNSVGFilter.h" #import "RNSVGFilter.h"
#import "RNSVGFilterPrimitive.h" #import "RNSVGFilterPrimitive.h"
#import "RNSVGRenderUtils.h"
#ifdef RCT_NEW_ARCH_ENABLED #ifdef RCT_NEW_ARCH_ENABLED
#import <React/RCTConversions.h> #import <React/RCTConversions.h>
@@ -97,7 +98,11 @@ using namespace facebook::react;
for (RNSVGNode *node in self.subviews) { for (RNSVGNode *node in self.subviews) {
if ([node isKindOfClass:[RNSVGFilterPrimitive class]]) { if ([node isKindOfClass:[RNSVGFilterPrimitive class]]) {
currentFilter = (RNSVGFilterPrimitive *)node; currentFilter = (RNSVGFilterPrimitive *)node;
result = [currentFilter applyFilter:resultsMap previousFilterResult:result]; CGImageRef cgResult = [[RNSVGRenderUtils sharedCIContext] createCGImage:[currentFilter applyFilter:resultsMap
previousFilterResult:result]
fromRect:[result extent]];
result = [CIImage imageWithCGImage:cgResult];
CGImageRelease(cgResult);
if (currentFilter.result) { if (currentFilter.result) {
[resultsMap setObject:result forKey:currentFilter.result]; [resultsMap setObject:result forKey:currentFilter.result];
} }
+1
View File
@@ -22,6 +22,7 @@ import Test2248 from './src/Test2248';
import Test2266 from './src/Test2266'; import Test2266 from './src/Test2266';
import Test2276 from './src/Test2276'; import Test2276 from './src/Test2276';
import Test2327 from './src/Test2327'; import Test2327 from './src/Test2327';
import Test2366 from './src/Test2366';
export default function App() { export default function App() {
return <ColorTest />; return <ColorTest />;
+30
View File
@@ -0,0 +1,30 @@
import React from 'react';
import {View} from 'react-native';
import {FeColorMatrix, Filter, Rect, Svg} from 'react-native-svg';
export default () => {
return (
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<Svg height="200" width="200">
<Filter id="filter">
<FeColorMatrix
type="matrix"
values="
78 -70 -7 0 0
-21 29 -7 0 0
-21 -70 0 0 0
0 0 0 1 0"
/>
<FeColorMatrix
type="matrix"
values="0.2126, 0.7152, 0.0722, 0, 0,
0.2126, 0.7152, 0.0722, 0, 0,
0.2126, 0.7152, 0, 0, 0,
0, 0, 0, 1, 0"
/>
</Filter>
<Rect width="200" height="200" fill="red" filter="url(#filter)" />
</Svg>
</View>
);
};