mirror of
https://github.com/zoriya/react-native-svg.git
synced 2026-06-04 23:54:53 +00:00
feat: add FeMerge and FeMergeNode filters (#2369)
# Summary As mentioned in #2362 Introduce new filters: * `FeMerge` * `FeMergeNode` ## Example usage ```tsx <Svg width="200" height="200"> <Filter id="mergeWithOffset" width="180" height="180"> <FeOffset dx="50" dy="50" result="test" /> <FeOffset dx="100" dy="100" in="SourceGraphic" /> <FeMerge> <FeMergeNode in="SourceGraphic" /> <FeMergeNode in="test" /> <FeMergeNode /> </FeMerge> </Filter> <Rect x="0" y="0" width="100" height="100" stroke="black" fill="red" filter="url(#mergeWithOffset)" /> </Svg> ``` <img width="207" alt="image" src="https://github.com/user-attachments/assets/9cb3ded6-f939-4b2b-8ece-df54e64fe898"> ## Test Plan `Example` app -> `Filters` -> `FeMerge` ## Compatibility | OS | Implemented | | ------- | :---------: | | iOS | ✅ | | Android | ✅ | ## Checklist - [x] I have tested this on a device and a simulator - [x] I added documentation in `README.md` - [x] I updated the typed files (typescript)
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
#import "RNSVGFilterPrimitive.h"
|
||||
|
||||
@interface RNSVGFeMerge : RNSVGFilterPrimitive
|
||||
|
||||
@property (nonatomic, copy) NSArray<NSString *> *nodes;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,105 @@
|
||||
#import "RNSVGFeMerge.h"
|
||||
|
||||
#ifdef RCT_NEW_ARCH_ENABLED
|
||||
#import <React/RCTConversions.h>
|
||||
#import <React/RCTFabricComponentsPlugins.h>
|
||||
#import <react/renderer/components/rnsvg/ComponentDescriptors.h>
|
||||
#import <react/renderer/components/view/conversions.h>
|
||||
#import "RNSVGFabricConversions.h"
|
||||
#endif // RCT_NEW_ARCH_ENABLED
|
||||
|
||||
@implementation RNSVGFeMerge
|
||||
|
||||
#ifdef RCT_NEW_ARCH_ENABLED
|
||||
using namespace facebook::react;
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame
|
||||
{
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
static const auto defaultProps = std::make_shared<const RNSVGFeMergeProps>();
|
||||
_props = defaultProps;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - RCTComponentViewProtocol
|
||||
|
||||
+ (ComponentDescriptorProvider)componentDescriptorProvider
|
||||
{
|
||||
return concreteComponentDescriptorProvider<RNSVGFeMergeComponentDescriptor>();
|
||||
}
|
||||
|
||||
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
||||
{
|
||||
const auto &newProps = static_cast<const RNSVGFeMergeProps &>(*props);
|
||||
|
||||
if (newProps.nodes.size() > 0) {
|
||||
NSMutableArray *nodesArray = [NSMutableArray new];
|
||||
for (auto node : newProps.nodes) {
|
||||
id json = RNSVGConvertFollyDynamicToId(node);
|
||||
if ([json isKindOfClass:[NSString class]]) {
|
||||
[nodesArray addObject:[json stringValue]];
|
||||
} else {
|
||||
[nodesArray addObject:[NSNull null]];
|
||||
}
|
||||
}
|
||||
self.nodes = nodesArray;
|
||||
}
|
||||
|
||||
setCommonFilterProps(newProps, self);
|
||||
_props = std::static_pointer_cast<RNSVGFeMergeProps const>(props);
|
||||
}
|
||||
|
||||
- (void)prepareForRecycle
|
||||
{
|
||||
[super prepareForRecycle];
|
||||
_nodes = nil;
|
||||
}
|
||||
#endif // RCT_NEW_ARCH_ENABLED
|
||||
|
||||
- (void)setNodes:(NSArray<NSString *> *)nodes
|
||||
{
|
||||
if (nodes == _nodes) {
|
||||
return;
|
||||
}
|
||||
|
||||
_nodes = nodes;
|
||||
[self invalidate];
|
||||
}
|
||||
|
||||
- (CIImage *)applyFilter:(NSMutableDictionary<NSString *, CIImage *> *)results
|
||||
previousFilterResult:(CIImage *)previous
|
||||
ctm:(CGAffineTransform)ctm
|
||||
{
|
||||
CIFilter *filter = [CIFilter filterWithName:@"CISourceOverCompositing"];
|
||||
[filter setDefaults];
|
||||
|
||||
CIImage *result;
|
||||
|
||||
for (int i = 0; i < [self.nodes count]; i++) {
|
||||
NSString *nodeKey = [self.nodes objectAtIndex:i];
|
||||
CIImage *inputImage =
|
||||
[nodeKey isEqual:[NSNull null]] ? previous : [results objectForKey:[self.nodes objectAtIndex:i]];
|
||||
if (inputImage == nil) {
|
||||
continue;
|
||||
}
|
||||
if (result == nil) {
|
||||
result = inputImage;
|
||||
continue;
|
||||
}
|
||||
[filter setValue:result forKey:@"inputBackgroundImage"];
|
||||
[filter setValue:inputImage forKey:@"inputImage"];
|
||||
|
||||
result = [filter valueForKey:@"outputImage"];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef RCT_NEW_ARCH_ENABLED
|
||||
Class<RCTComponentViewProtocol> RNSVGFeMergeCls(void)
|
||||
{
|
||||
return RNSVGFeMerge.class;
|
||||
}
|
||||
#endif // RCT_NEW_ARCH_ENABLED
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user