mirror of
https://github.com/zoriya/react-native-svg.git
synced 2025-12-06 07:06:11 +00:00
feat: add FeOffset filter (#2361)
# Summary Continuation of #2316 Introducing new filter `FeOffset`. ## Test Plan Example app -> Filters -> FeOffset ## 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:
9
apple/Filters/RNSVGFeOffset.h
Normal file
9
apple/Filters/RNSVGFeOffset.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#import "RNSVGFilterPrimitive.h"
|
||||
|
||||
@interface RNSVGFeOffset : RNSVGFilterPrimitive
|
||||
|
||||
@property (nonatomic, strong) NSString *in1;
|
||||
@property (nonatomic, strong) RNSVGLength *dx;
|
||||
@property (nonatomic, strong) RNSVGLength *dy;
|
||||
|
||||
@end
|
||||
126
apple/Filters/RNSVGFeOffset.mm
Normal file
126
apple/Filters/RNSVGFeOffset.mm
Normal file
@@ -0,0 +1,126 @@
|
||||
#import "RNSVGFeOffset.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 RNSVGFeOffset
|
||||
|
||||
#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 RNSVGFeOffsetProps>();
|
||||
_props = defaultProps;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - RCTComponentViewProtocol
|
||||
|
||||
+ (ComponentDescriptorProvider)componentDescriptorProvider
|
||||
{
|
||||
return concreteComponentDescriptorProvider<RNSVGFeOffsetComponentDescriptor>();
|
||||
}
|
||||
|
||||
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
||||
{
|
||||
const auto &newProps = static_cast<const RNSVGFeOffsetProps &>(*props);
|
||||
|
||||
self.in1 = RCTNSStringFromStringNilIfEmpty(newProps.in1);
|
||||
id dx = RNSVGConvertFollyDynamicToId(newProps.dx);
|
||||
if (dx != nil) {
|
||||
self.dx = [RCTConvert RNSVGLength:dx];
|
||||
}
|
||||
id dy = RNSVGConvertFollyDynamicToId(newProps.dy);
|
||||
if (dy != nil) {
|
||||
self.dy = [RCTConvert RNSVGLength:dy];
|
||||
}
|
||||
|
||||
setCommonFilterProps(newProps, self);
|
||||
_props = std::static_pointer_cast<RNSVGFeOffsetProps const>(props);
|
||||
}
|
||||
|
||||
- (void)prepareForRecycle
|
||||
{
|
||||
[super prepareForRecycle];
|
||||
_in1 = nil;
|
||||
_dx = nil;
|
||||
_dy = nil;
|
||||
}
|
||||
#endif // RCT_NEW_ARCH_ENABLED
|
||||
|
||||
- (void)setIn1:(NSString *)in1
|
||||
{
|
||||
if ([in1 isEqualToString:_in1]) {
|
||||
return;
|
||||
}
|
||||
|
||||
_in1 = in1;
|
||||
[self invalidate];
|
||||
}
|
||||
|
||||
- (void)setDx:(RNSVGLength *)dx
|
||||
{
|
||||
if ([dx isEqualTo:_dx]) {
|
||||
return;
|
||||
}
|
||||
|
||||
_dx = dx;
|
||||
[self invalidate];
|
||||
}
|
||||
|
||||
- (void)setDy:(RNSVGLength *)dy
|
||||
{
|
||||
if ([dy isEqualTo:_dy]) {
|
||||
return;
|
||||
}
|
||||
|
||||
_dy = dy;
|
||||
[self invalidate];
|
||||
}
|
||||
|
||||
- (CIImage *)applyFilter:(NSMutableDictionary<NSString *, CIImage *> *)results
|
||||
previousFilterResult:(CIImage *)previous
|
||||
ctm:(CGAffineTransform)ctm
|
||||
{
|
||||
CIImage *inResults = self.in1 ? [results objectForKey:self.in1] : nil;
|
||||
CIImage *inputImage = inResults ? inResults : previous;
|
||||
|
||||
if (!inputImage) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
CIFilter *filter = [CIFilter filterWithName:@"CIAffineTransform"];
|
||||
[filter setDefaults];
|
||||
[filter setValue:inputImage forKey:@"inputImage"];
|
||||
|
||||
CGFloat dx = [self relativeOnWidth:self.dx];
|
||||
CGFloat dy = [self relativeOnWidth:self.dy];
|
||||
|
||||
// reset ctm translation
|
||||
CGAffineTransform contextTransform = CGAffineTransformConcat(ctm, CGAffineTransformMakeTranslation(-ctm.tx, -ctm.ty));
|
||||
|
||||
CGPoint translate = CGPointMake(dx, dy);
|
||||
translate = CGPointApplyAffineTransform(translate, contextTransform);
|
||||
CGAffineTransform transform = CGAffineTransformMakeTranslation(translate.x, translate.y);
|
||||
|
||||
[filter setValue:[NSValue valueWithCGAffineTransform:transform] forKey:@"inputTransform"];
|
||||
|
||||
return [filter valueForKey:@"outputImage"];
|
||||
}
|
||||
|
||||
#ifdef RCT_NEW_ARCH_ENABLED
|
||||
Class<RCTComponentViewProtocol> RNSVGFeOffsetCls(void)
|
||||
{
|
||||
return RNSVGFeOffset.class;
|
||||
}
|
||||
#endif // RCT_NEW_ARCH_ENABLED
|
||||
|
||||
@end
|
||||
@@ -99,7 +99,8 @@ using namespace facebook::react;
|
||||
if ([node isKindOfClass:[RNSVGFilterPrimitive class]]) {
|
||||
currentFilter = (RNSVGFilterPrimitive *)node;
|
||||
CGImageRef cgResult = [[RNSVGRenderUtils sharedCIContext] createCGImage:[currentFilter applyFilter:resultsMap
|
||||
previousFilterResult:result]
|
||||
previousFilterResult:result
|
||||
ctm:ctm]
|
||||
fromRect:[result extent]];
|
||||
result = [CIImage imageWithCGImage:cgResult];
|
||||
CGImageRelease(cgResult);
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
@property (nonatomic, strong) NSString *result;
|
||||
|
||||
- (CIImage *)applyFilter:(NSMutableDictionary<NSString *, CIImage *> *)results previousFilterResult:(CIImage *)previous;
|
||||
- (CIImage *)applyFilter:(NSMutableDictionary<NSString *, CIImage *> *)results
|
||||
previousFilterResult:(CIImage *)previous
|
||||
ctm:(CGAffineTransform)ctm;
|
||||
- (CIImage *)cropResult:(CIImage *)result;
|
||||
|
||||
@end
|
||||
|
||||
@@ -93,6 +93,13 @@
|
||||
return previous;
|
||||
}
|
||||
|
||||
- (CIImage *)applyFilter:(NSMutableDictionary<NSString *, CIImage *> *)results
|
||||
previousFilterResult:(CIImage *)previous
|
||||
ctm:(CGAffineTransform)ctm
|
||||
{
|
||||
return [self applyFilter:results previousFilterResult:previous];
|
||||
}
|
||||
|
||||
- (CIImage *)cropResult:(CIImage *)result
|
||||
{
|
||||
CIFilter *filter = [CIFilter filterWithName:@"CICrop"];
|
||||
|
||||
5
apple/ViewManagers/RNSVGFeOffsetManager.h
Normal file
5
apple/ViewManagers/RNSVGFeOffsetManager.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#import "RNSVGFilterPrimitiveManager.h"
|
||||
|
||||
@interface RNSVGFeOffsetManager : RNSVGFilterPrimitiveManager
|
||||
|
||||
@end
|
||||
17
apple/ViewManagers/RNSVGFeOffsetManager.mm
Normal file
17
apple/ViewManagers/RNSVGFeOffsetManager.mm
Normal file
@@ -0,0 +1,17 @@
|
||||
#import "RNSVGFeOffsetManager.h"
|
||||
#import "RNSVGFeOffset.h"
|
||||
|
||||
@implementation RNSVGFeOffsetManager
|
||||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
- (RNSVGFeOffset *)node
|
||||
{
|
||||
return [RNSVGFeOffset new];
|
||||
}
|
||||
|
||||
RCT_EXPORT_VIEW_PROPERTY(in1, NSString)
|
||||
RCT_EXPORT_VIEW_PROPERTY(dx, RNSVGLength *)
|
||||
RCT_EXPORT_VIEW_PROPERTY(dy, RNSVGLength *)
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user