mirror of
https://github.com/zoriya/react-native-svg.git
synced 2025-12-06 07:06:11 +00:00
feat: add FeGaussianBlur filter (#2352)
# Summary Continuation of #2316 Introducing new filter `FeGaussianBlur`. ### Implementation notes On Android there is no easy way to fully implement Gaussian blur, as there is no native api for this. While a basic implementation is possible with `RenderScript`, it does not allow for blur in one axis and greater than `25` ## Test Plan Example app -> Filters -> FeGaussianBlur ## Compatibility | OS | Implemented | | ------- | :---------: | | iOS | ✅ | | Android | ✅ |
This commit is contained in:
1
USAGE.md
1
USAGE.md
@@ -1260,6 +1260,7 @@ Filter effects are a way of processing an element’s rendering before it is dis
|
||||
Currently supported\* filters are:
|
||||
|
||||
- FeColorMatrix
|
||||
- FeGaussianBlur
|
||||
|
||||
\*_More filters are coming soon_
|
||||
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
package com.horcrux.svg;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.renderscript.Allocation;
|
||||
import android.renderscript.Element;
|
||||
import android.renderscript.RenderScript;
|
||||
import android.renderscript.ScriptIntrinsicBlur;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import java.util.HashMap;
|
||||
|
||||
@SuppressLint("ViewConstructor")
|
||||
class FeGaussianBlurView extends FilterPrimitiveView {
|
||||
String mIn1;
|
||||
float mStdDeviationX;
|
||||
float mStdDeviationY;
|
||||
FilterProperties.EdgeMode mEdgeMode;
|
||||
|
||||
public FeGaussianBlurView(ReactContext reactContext) {
|
||||
super(reactContext);
|
||||
}
|
||||
|
||||
public void setIn1(String in1) {
|
||||
this.mIn1 = in1;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setStdDeviationX(float stdDeviationX) {
|
||||
this.mStdDeviationX = stdDeviationX;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setStdDeviationY(float stdDeviationY) {
|
||||
this.mStdDeviationY = stdDeviationY;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setEdgeMode(String edgeMode) {
|
||||
this.mEdgeMode = FilterProperties.EdgeMode.getEnum(edgeMode);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bitmap applyFilter(HashMap<String, Bitmap> resultsMap, Bitmap prevResult) {
|
||||
Bitmap source = getSource(resultsMap, prevResult, this.mIn1);
|
||||
return blur(getContext(), source);
|
||||
}
|
||||
|
||||
private Bitmap blur(Context context, Bitmap bitmap) {
|
||||
// Android blur radius is much weaker than SVG's, so we need to scale it up.
|
||||
float stdDeviation = Math.max(mStdDeviationX, mStdDeviationY) * 2;
|
||||
if (stdDeviation <= 0) return bitmap;
|
||||
final float maxRadius = 25.0f;
|
||||
float radius = Math.min(stdDeviation, maxRadius);
|
||||
|
||||
Bitmap outputBitmap = Bitmap.createBitmap(bitmap);
|
||||
|
||||
// Create a RenderScript with blur
|
||||
RenderScript rs = RenderScript.create(context);
|
||||
ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
|
||||
|
||||
// Allocate memory for Renderscript to work with
|
||||
Allocation tmpIn = Allocation.createFromBitmap(rs, bitmap);
|
||||
Allocation tmpOut = Allocation.createFromBitmap(rs, outputBitmap);
|
||||
|
||||
// Set the radius of the blur, allocation input, and output
|
||||
blurScript.setRadius(radius);
|
||||
blurScript.setInput(tmpIn);
|
||||
blurScript.forEach(tmpOut);
|
||||
|
||||
// Copy the allocation output to the output bitmap and release memory
|
||||
tmpOut.copyTo(outputBitmap);
|
||||
tmpIn.destroy();
|
||||
tmpOut.destroy();
|
||||
rs.destroy();
|
||||
|
||||
return Bitmap.createScaledBitmap(outputBitmap, bitmap.getWidth(), bitmap.getHeight(), false);
|
||||
}
|
||||
}
|
||||
@@ -105,6 +105,8 @@ import com.facebook.react.viewmanagers.RNSVGEllipseManagerDelegate;
|
||||
import com.facebook.react.viewmanagers.RNSVGEllipseManagerInterface;
|
||||
import com.facebook.react.viewmanagers.RNSVGFeColorMatrixManagerDelegate;
|
||||
import com.facebook.react.viewmanagers.RNSVGFeColorMatrixManagerInterface;
|
||||
import com.facebook.react.viewmanagers.RNSVGFeGaussianBlurManagerDelegate;
|
||||
import com.facebook.react.viewmanagers.RNSVGFeGaussianBlurManagerInterface;
|
||||
import com.facebook.react.viewmanagers.RNSVGFilterManagerDelegate;
|
||||
import com.facebook.react.viewmanagers.RNSVGFilterManagerInterface;
|
||||
import com.facebook.react.viewmanagers.RNSVGForeignObjectManagerDelegate;
|
||||
@@ -584,6 +586,7 @@ class VirtualViewManager<V extends VirtualView> extends ViewGroupManager<Virtual
|
||||
RNSVGMask,
|
||||
RNSVGFilter,
|
||||
RNSVGFeColorMatrix,
|
||||
RNSVGFeGaussianBlur,
|
||||
RNSVGMarker,
|
||||
RNSVGForeignObject,
|
||||
}
|
||||
@@ -632,6 +635,8 @@ class VirtualViewManager<V extends VirtualView> extends ViewGroupManager<Virtual
|
||||
return new FilterView(reactContext);
|
||||
case RNSVGFeColorMatrix:
|
||||
return new FeColorMatrixView(reactContext);
|
||||
case RNSVGFeGaussianBlur:
|
||||
return new FeGaussianBlurView(reactContext);
|
||||
case RNSVGMarker:
|
||||
return new MarkerView(reactContext);
|
||||
case RNSVGForeignObject:
|
||||
@@ -1387,6 +1392,61 @@ class RenderableViewManager<T extends RenderableView> extends VirtualViewManager
|
||||
}
|
||||
}
|
||||
|
||||
static class FeGaussianBlurManager extends VirtualViewManager<FeGaussianBlurView>
|
||||
implements RNSVGFeGaussianBlurManagerInterface<FeGaussianBlurView> {
|
||||
FeGaussianBlurManager() {
|
||||
super(SVGClass.RNSVGFeGaussianBlur);
|
||||
mDelegate = new RNSVGFeGaussianBlurManagerDelegate(this);
|
||||
}
|
||||
|
||||
public static final String REACT_CLASS = "RNSVGFeGaussianBlur";
|
||||
|
||||
@ReactProp(name = "x")
|
||||
public void setX(FeGaussianBlurView node, Dynamic x) {
|
||||
node.setX(x);
|
||||
}
|
||||
|
||||
@ReactProp(name = "y")
|
||||
public void setY(FeGaussianBlurView node, Dynamic y) {
|
||||
node.setY(y);
|
||||
}
|
||||
|
||||
@ReactProp(name = "width")
|
||||
public void setWidth(FeGaussianBlurView node, Dynamic width) {
|
||||
node.setWidth(width);
|
||||
}
|
||||
|
||||
@ReactProp(name = "height")
|
||||
public void setHeight(FeGaussianBlurView node, Dynamic height) {
|
||||
node.setHeight(height);
|
||||
}
|
||||
|
||||
@ReactProp(name = "result")
|
||||
public void setResult(FeGaussianBlurView node, String result) {
|
||||
node.setResult(result);
|
||||
}
|
||||
|
||||
@ReactProp(name = "in1")
|
||||
public void setIn1(FeGaussianBlurView node, String in1) {
|
||||
node.setIn1(in1);
|
||||
}
|
||||
|
||||
@ReactProp(name = "stdDeviationX")
|
||||
public void setStdDeviationX(FeGaussianBlurView node, float stdDeviationX) {
|
||||
node.setStdDeviationX(stdDeviationX);
|
||||
}
|
||||
|
||||
@ReactProp(name = "stdDeviationY")
|
||||
public void setStdDeviationY(FeGaussianBlurView node, float stdDeviationY) {
|
||||
node.setStdDeviationY(stdDeviationY);
|
||||
}
|
||||
|
||||
@ReactProp(name = "values")
|
||||
public void setEdgeMode(FeGaussianBlurView node, String edgeMode) {
|
||||
node.setEdgeMode(edgeMode);
|
||||
}
|
||||
}
|
||||
|
||||
static class ForeignObjectManager extends GroupViewManagerAbstract<ForeignObjectView>
|
||||
implements RNSVGForeignObjectManagerInterface<ForeignObjectView> {
|
||||
ForeignObjectManager() {
|
||||
|
||||
@@ -223,6 +223,15 @@ public class SvgPackage extends TurboReactPackage implements ViewManagerOnDemand
|
||||
return new FeColorMatrixManager();
|
||||
}
|
||||
}));
|
||||
specs.put(
|
||||
FeGaussianBlurManager.REACT_CLASS,
|
||||
ModuleSpec.viewManagerSpec(
|
||||
new Provider<NativeModule>() {
|
||||
@Override
|
||||
public NativeModule get() {
|
||||
return new FeGaussianBlurManager();
|
||||
}
|
||||
}));
|
||||
specs.put(
|
||||
ForeignObjectManager.REACT_CLASS,
|
||||
ModuleSpec.viewManagerSpec(
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
|
||||
*
|
||||
* Do not edit this file as changes may cause incorrect behavior and will be lost
|
||||
* once the code is regenerated.
|
||||
*
|
||||
* @generated by codegen project: GeneratePropsJavaDelegate.js
|
||||
*/
|
||||
|
||||
package com.facebook.react.viewmanagers;
|
||||
|
||||
import android.view.View;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.facebook.react.bridge.DynamicFromObject;
|
||||
import com.facebook.react.uimanager.BaseViewManagerDelegate;
|
||||
import com.facebook.react.uimanager.BaseViewManagerInterface;
|
||||
|
||||
public class RNSVGFeGaussianBlurManagerDelegate<T extends View, U extends BaseViewManagerInterface<T> & RNSVGFeGaussianBlurManagerInterface<T>> extends BaseViewManagerDelegate<T, U> {
|
||||
public RNSVGFeGaussianBlurManagerDelegate(U viewManager) {
|
||||
super(viewManager);
|
||||
}
|
||||
@Override
|
||||
public void setProperty(T view, String propName, @Nullable Object value) {
|
||||
switch (propName) {
|
||||
case "x":
|
||||
mViewManager.setX(view, new DynamicFromObject(value));
|
||||
break;
|
||||
case "y":
|
||||
mViewManager.setY(view, new DynamicFromObject(value));
|
||||
break;
|
||||
case "width":
|
||||
mViewManager.setWidth(view, new DynamicFromObject(value));
|
||||
break;
|
||||
case "height":
|
||||
mViewManager.setHeight(view, new DynamicFromObject(value));
|
||||
break;
|
||||
case "result":
|
||||
mViewManager.setResult(view, value == null ? null : (String) value);
|
||||
break;
|
||||
case "in1":
|
||||
mViewManager.setIn1(view, value == null ? null : (String) value);
|
||||
break;
|
||||
case "stdDeviationX":
|
||||
mViewManager.setStdDeviationX(view, value == null ? 0f : ((Double) value).floatValue());
|
||||
break;
|
||||
case "stdDeviationY":
|
||||
mViewManager.setStdDeviationY(view, value == null ? 0f : ((Double) value).floatValue());
|
||||
break;
|
||||
case "edgeMode":
|
||||
mViewManager.setEdgeMode(view, (String) value);
|
||||
break;
|
||||
default:
|
||||
super.setProperty(view, propName, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
|
||||
*
|
||||
* Do not edit this file as changes may cause incorrect behavior and will be lost
|
||||
* once the code is regenerated.
|
||||
*
|
||||
* @generated by codegen project: GeneratePropsJavaInterface.js
|
||||
*/
|
||||
|
||||
package com.facebook.react.viewmanagers;
|
||||
|
||||
import android.view.View;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.facebook.react.bridge.Dynamic;
|
||||
|
||||
public interface RNSVGFeGaussianBlurManagerInterface<T extends View> {
|
||||
void setX(T view, Dynamic value);
|
||||
void setY(T view, Dynamic value);
|
||||
void setWidth(T view, Dynamic value);
|
||||
void setHeight(T view, Dynamic value);
|
||||
void setResult(T view, @Nullable String value);
|
||||
void setIn1(T view, @Nullable String value);
|
||||
void setStdDeviationX(T view, float value);
|
||||
void setStdDeviationY(T view, float value);
|
||||
void setEdgeMode(T view, @Nullable String value);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
typedef CF_ENUM(int32_t, RNSVGEdgeModeTypes) {
|
||||
typedef CF_ENUM(int32_t, RNSVGEdgeMode) {
|
||||
SVG_EDGEMODE_UNKNOWN,
|
||||
SVG_EDGEMODE_DUPLICATE,
|
||||
SVG_EDGEMODE_WRAP,
|
||||
@@ -160,8 +160,6 @@ using namespace facebook::react;
|
||||
[filter setValue:inputImage forKey:@"inputImage"];
|
||||
|
||||
return [filter valueForKey:@"outputImage"];
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
#ifdef RCT_NEW_ARCH_ENABLED
|
||||
|
||||
11
apple/Filters/RNSVGFeGaussianBlur.h
Normal file
11
apple/Filters/RNSVGFeGaussianBlur.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#import "RNSVGEdgeMode.h"
|
||||
#import "RNSVGFilterPrimitive.h"
|
||||
|
||||
@interface RNSVGFeGaussianBlur : RNSVGFilterPrimitive
|
||||
|
||||
@property (nonatomic, strong) NSString *in1;
|
||||
@property (nonatomic, strong) NSNumber *stdDeviationX;
|
||||
@property (nonatomic, strong) NSNumber *stdDeviationY;
|
||||
@property (nonatomic, assign) RNSVGEdgeMode edgeMode;
|
||||
|
||||
@end
|
||||
129
apple/Filters/RNSVGFeGaussianBlur.mm
Normal file
129
apple/Filters/RNSVGFeGaussianBlur.mm
Normal file
@@ -0,0 +1,129 @@
|
||||
#import "RNSVGFeGaussianBlur.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 "RNSVGConvert.h"
|
||||
#import "RNSVGFabricConversions.h"
|
||||
#endif // RCT_NEW_ARCH_ENABLED
|
||||
|
||||
@implementation RNSVGFeGaussianBlur
|
||||
|
||||
#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 RNSVGFeGaussianBlurProps>();
|
||||
_props = defaultProps;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - RCTComponentViewProtocol
|
||||
|
||||
+ (ComponentDescriptorProvider)componentDescriptorProvider
|
||||
{
|
||||
return concreteComponentDescriptorProvider<RNSVGFeGaussianBlurComponentDescriptor>();
|
||||
}
|
||||
|
||||
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
||||
{
|
||||
const auto &newProps = static_cast<const RNSVGFeGaussianBlurProps &>(*props);
|
||||
|
||||
self.in1 = RCTNSStringFromStringNilIfEmpty(newProps.in1);
|
||||
self.stdDeviationX = [NSNumber numberWithFloat:newProps.stdDeviationX];
|
||||
self.stdDeviationY = [NSNumber numberWithFloat:newProps.stdDeviationY];
|
||||
self.edgeMode = [RNSVGConvert RNSVGEdgeModeFromCppEquivalent:newProps.edgeMode];
|
||||
|
||||
setCommonFilterProps(newProps, self);
|
||||
_props = std::static_pointer_cast<RNSVGFeGaussianBlurProps const>(props);
|
||||
}
|
||||
|
||||
- (void)prepareForRecycle
|
||||
{
|
||||
[super prepareForRecycle];
|
||||
_in1 = nil;
|
||||
_stdDeviationX = nil;
|
||||
_stdDeviationY = nil;
|
||||
_edgeMode = SVG_EDGEMODE_UNKNOWN;
|
||||
}
|
||||
#endif // RCT_NEW_ARCH_ENABLED
|
||||
|
||||
- (CIImage *)applyFilter:(NSMutableDictionary<NSString *, CIImage *> *)results previousFilterResult:(CIImage *)previous
|
||||
{
|
||||
CIImage *inResults = self.in1 ? [results objectForKey:self.in1] : nil;
|
||||
CIImage *inputImage = inResults ? inResults : previous;
|
||||
|
||||
if (!inputImage) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
CIFilter *filter = [CIFilter filterWithName:(_stdDeviationX == _stdDeviationY ? @"CIGaussianBlur" : @"CIMotionBlur")];
|
||||
[filter setDefaults];
|
||||
[filter setValue:inputImage forKey:@"inputImage"];
|
||||
[filter setValue:_stdDeviationX forKey:@"inputRadius"];
|
||||
|
||||
if (_stdDeviationX != _stdDeviationY) {
|
||||
// X axis
|
||||
[filter setValue:[NSNumber numberWithFloat:0] forKey:@"inputAngle"];
|
||||
// Y axis
|
||||
[filter setValue:[filter valueForKey:@"outputImage"] forKey:@"inputImage"];
|
||||
[filter setValue:_stdDeviationY forKey:@"inputRadius"];
|
||||
[filter setValue:[NSNumber numberWithFloat:M_PI_2] forKey:@"inputAngle"];
|
||||
}
|
||||
|
||||
return [filter valueForKey:@"outputImage"];
|
||||
}
|
||||
|
||||
- (void)setIn1:(NSString *)in1
|
||||
{
|
||||
if ([in1 isEqualToString:_in1]) {
|
||||
return;
|
||||
}
|
||||
|
||||
_in1 = in1;
|
||||
[self invalidate];
|
||||
}
|
||||
|
||||
- (void)setStdDeviationX:(NSNumber *)stdDeviationX
|
||||
{
|
||||
if (stdDeviationX == _stdDeviationX) {
|
||||
return;
|
||||
}
|
||||
|
||||
_stdDeviationX = stdDeviationX;
|
||||
[self invalidate];
|
||||
}
|
||||
|
||||
- (void)setStdDeviationY:(NSNumber *)stdDeviationY
|
||||
{
|
||||
if (stdDeviationY == _stdDeviationY) {
|
||||
return;
|
||||
}
|
||||
|
||||
_stdDeviationY = stdDeviationY;
|
||||
[self invalidate];
|
||||
}
|
||||
|
||||
- (void)setEdgeMode:(RNSVGEdgeMode)edgeMode
|
||||
{
|
||||
if (edgeMode == _edgeMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
_edgeMode = edgeMode;
|
||||
[self invalidate];
|
||||
}
|
||||
|
||||
#ifdef RCT_NEW_ARCH_ENABLED
|
||||
Class<RCTComponentViewProtocol> RNSVGFeGaussianBlurCls(void)
|
||||
{
|
||||
return RNSVGFeGaussianBlur.class;
|
||||
}
|
||||
#endif // RCT_NEW_ARCH_ENABLED
|
||||
|
||||
@end
|
||||
@@ -12,7 +12,7 @@
|
||||
#import "RCTConvert+RNSVG.h"
|
||||
#import "RNSVGCGFCRule.h"
|
||||
#import "RNSVGColorMatrixType.h"
|
||||
#import "RNSVGEdgeModeTypes.h"
|
||||
#import "RNSVGEdgeMode.h"
|
||||
#import "RNSVGLength.h"
|
||||
#import "RNSVGMaskType.h"
|
||||
#import "RNSVGPathParser.h"
|
||||
|
||||
@@ -52,13 +52,13 @@ RCT_ENUM_CONVERTER(
|
||||
intValue)
|
||||
|
||||
RCT_ENUM_CONVERTER(
|
||||
RNSVGEdgeModeTypes,
|
||||
RNSVGEdgeMode,
|
||||
(@{
|
||||
@"duplicate" : @(SVG_EDGEMODE_DUPLICATE),
|
||||
@"wrap" : @(SVG_EDGEMODE_WRAP),
|
||||
@"none" : @(SVG_EDGEMODE_NONE),
|
||||
}),
|
||||
SVG_FECOLORMATRIX_TYPE_UNKNOWN,
|
||||
SVG_EDGEMODE_UNKNOWN,
|
||||
intValue)
|
||||
|
||||
RCT_ENUM_CONVERTER(
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifdef RCT_NEW_ARCH_ENABLED
|
||||
#import <react/renderer/components/rnsvg/Props.h>
|
||||
#import "RNSVGColorMatrixType.h"
|
||||
#import "RNSVGEdgeModeTypes.h"
|
||||
#import "RNSVGEdgeMode.h"
|
||||
#import "RNSVGUnits.h"
|
||||
|
||||
namespace react = facebook::react;
|
||||
@@ -11,6 +11,7 @@ namespace react = facebook::react;
|
||||
+ (RNSVGUnits)RNSVGUnitsFromFilterUnitsCppEquivalent:(react::RNSVGFilterFilterUnits)svgUnits;
|
||||
+ (RNSVGUnits)RNSVGUnitsFromPrimitiveUnitsCppEquivalent:(react::RNSVGFilterPrimitiveUnits)svgUnits;
|
||||
+ (RNSVGColorMatrixType)RNSVGColorMatrixTypeFromCppEquivalent:(react::RNSVGFeColorMatrixType)type;
|
||||
+ (RNSVGEdgeMode)RNSVGEdgeModeFromCppEquivalent:(react::RNSVGFeGaussianBlurEdgeMode)edgeMode;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
+ (RNSVGColorMatrixType)RNSVGColorMatrixTypeFromCppEquivalent:(react::RNSVGFeColorMatrixType)type;
|
||||
+ (RNSVGColorMatrixType)RNSVGColorMatrixTypeFromCppEquivalent:(react::RNSVGFeColorMatrixType)type
|
||||
{
|
||||
switch (type) {
|
||||
case react::RNSVGFeColorMatrixType::Matrix:
|
||||
@@ -37,6 +37,20 @@
|
||||
}
|
||||
}
|
||||
|
||||
+ (RNSVGEdgeMode)RNSVGEdgeModeFromCppEquivalent:(react::RNSVGFeGaussianBlurEdgeMode)edgeMode
|
||||
{
|
||||
switch (edgeMode) {
|
||||
case react::RNSVGFeGaussianBlurEdgeMode::Duplicate:
|
||||
return SVG_EDGEMODE_DUPLICATE;
|
||||
case react::RNSVGFeGaussianBlurEdgeMode::Wrap:
|
||||
return SVG_EDGEMODE_WRAP;
|
||||
case react::RNSVGFeGaussianBlurEdgeMode::None:
|
||||
return SVG_EDGEMODE_NONE;
|
||||
default:
|
||||
return SVG_EDGEMODE_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif // RCT_NEW_ARCH_ENABLED
|
||||
|
||||
5
apple/ViewManagers/RNSVGFeGaussianBlurManager.h
Normal file
5
apple/ViewManagers/RNSVGFeGaussianBlurManager.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#import "RNSVGFilterPrimitiveManager.h"
|
||||
|
||||
@interface RNSVGFeGaussianBlurManager : RNSVGFilterPrimitiveManager
|
||||
|
||||
@end
|
||||
19
apple/ViewManagers/RNSVGFeGaussianBlurManager.mm
Normal file
19
apple/ViewManagers/RNSVGFeGaussianBlurManager.mm
Normal file
@@ -0,0 +1,19 @@
|
||||
#import "RNSVGFeGaussianBlurManager.h"
|
||||
#import "RNSVGEdgeMode.h"
|
||||
#import "RNSVGFeGaussianBlur.h"
|
||||
|
||||
@implementation RNSVGFeGaussianBlurManager
|
||||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
- (RNSVGFeGaussianBlur *)node
|
||||
{
|
||||
return [RNSVGFeGaussianBlur new];
|
||||
}
|
||||
|
||||
RCT_EXPORT_VIEW_PROPERTY(in1, NSString)
|
||||
RCT_EXPORT_VIEW_PROPERTY(stdDeviationX, NSNumber)
|
||||
RCT_EXPORT_VIEW_PROPERTY(stdDeviationY, NSNumber)
|
||||
RCT_EXPORT_VIEW_PROPERTY(edgeMode, RNSVGEdgeMode)
|
||||
|
||||
@end
|
||||
92
apps/examples/src/examples/Filters/FeGaussianBlur.tsx
Normal file
92
apps/examples/src/examples/Filters/FeGaussianBlur.tsx
Normal file
@@ -0,0 +1,92 @@
|
||||
import React, {Component} from 'react';
|
||||
import {Circle, FeGaussianBlur, Filter, G, Svg} from 'react-native-svg';
|
||||
|
||||
class StdDeviation5Example extends Component {
|
||||
static title = 'stdDeviation="5"';
|
||||
render() {
|
||||
return (
|
||||
<Svg height="150" width="150">
|
||||
<Filter id="filter">
|
||||
<FeGaussianBlur stdDeviation="5" />
|
||||
</Filter>
|
||||
<G filter="url(#filter)">
|
||||
<Circle cx="75" cy="50" r="40" fill="blue" fillOpacity="0.5" />
|
||||
<Circle cx="55" cy="90" r="40" fill="green" fillOpacity="0.5" />
|
||||
<Circle cx="95" cy="90" r="40" fill="red" fillOpacity="0.5" />
|
||||
</G>
|
||||
</Svg>
|
||||
);
|
||||
}
|
||||
}
|
||||
class StdDeviation20Example extends Component {
|
||||
static title = 'stdDeviation="20"';
|
||||
render() {
|
||||
return (
|
||||
<Svg height="150" width="150">
|
||||
<Filter id="filter">
|
||||
<FeGaussianBlur stdDeviation="20" />
|
||||
</Filter>
|
||||
<G filter="url(#filter)">
|
||||
<Circle cx="75" cy="50" r="40" fill="blue" fillOpacity="0.5" />
|
||||
<Circle cx="55" cy="90" r="40" fill="green" fillOpacity="0.5" />
|
||||
<Circle cx="95" cy="90" r="40" fill="red" fillOpacity="0.5" />
|
||||
</G>
|
||||
</Svg>
|
||||
);
|
||||
}
|
||||
}
|
||||
class StdDeviation250Example extends Component {
|
||||
static title = 'stdDeviation="25 0"';
|
||||
render() {
|
||||
return (
|
||||
<Svg height="150" width="150">
|
||||
<Filter id="filter">
|
||||
<FeGaussianBlur stdDeviation="25 0" />
|
||||
</Filter>
|
||||
<G filter="url(#filter)">
|
||||
<Circle cx="75" cy="50" r="40" fill="blue" fillOpacity="0.5" />
|
||||
<Circle cx="55" cy="90" r="40" fill="green" fillOpacity="0.5" />
|
||||
<Circle cx="95" cy="90" r="40" fill="red" fillOpacity="0.5" />
|
||||
</G>
|
||||
</Svg>
|
||||
);
|
||||
}
|
||||
}
|
||||
class StdDeviation050Example extends Component {
|
||||
static title = 'stdDeviation="0 50"';
|
||||
render() {
|
||||
return (
|
||||
<Svg height="150" width="150">
|
||||
<Filter id="filter">
|
||||
<FeGaussianBlur stdDeviation="0 50" />
|
||||
</Filter>
|
||||
<G filter="url(#filter)">
|
||||
<Circle cx="75" cy="50" r="40" fill="blue" fillOpacity="0.5" />
|
||||
<Circle cx="55" cy="90" r="40" fill="green" fillOpacity="0.5" />
|
||||
<Circle cx="95" cy="90" r="40" fill="red" fillOpacity="0.5" />
|
||||
</G>
|
||||
</Svg>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const icon = (
|
||||
<Svg height="30" width="30" viewBox="0 0 20 20">
|
||||
<Filter id="filter">
|
||||
<FeGaussianBlur stdDeviation="6" />
|
||||
</Filter>
|
||||
<G filter="url(#filter)">
|
||||
<Circle cx="10" cy="7.5" r="5" fill="blue" fillOpacity="0.5" />
|
||||
<Circle cx="7.5" cy="12.5" r="5" fill="green" fillOpacity="0.5" />
|
||||
<Circle cx="12.5" cy="12.5" r="5" fill="red" fillOpacity="0.5" />
|
||||
</G>
|
||||
</Svg>
|
||||
);
|
||||
|
||||
const samples = [
|
||||
StdDeviation5Example,
|
||||
StdDeviation20Example,
|
||||
StdDeviation250Example,
|
||||
StdDeviation050Example,
|
||||
];
|
||||
export {icon, samples};
|
||||
@@ -1,3 +1,4 @@
|
||||
import * as FeColorMatrix from './FeColorMatrix';
|
||||
import * as FeGaussianBlur from './FeGaussianBlur';
|
||||
import * as ReanimatedFeColorMatrix from './ReanimatedFeColorMatrix';
|
||||
export {FeColorMatrix, ReanimatedFeColorMatrix};
|
||||
export {FeColorMatrix, FeGaussianBlur, ReanimatedFeColorMatrix};
|
||||
|
||||
@@ -1051,7 +1051,7 @@ PODS:
|
||||
- React-jsi (= 0.73.32)
|
||||
- React-logger (= 0.73.32)
|
||||
- React-perflogger (= 0.73.32)
|
||||
- RNReanimated (3.9.0):
|
||||
- RNReanimated (3.9.0-nightly-20240421-474f6983d):
|
||||
- glog
|
||||
- RCT-Folly (= 2022.05.16.00)
|
||||
- RCTRequired
|
||||
@@ -1324,7 +1324,7 @@ SPEC CHECKSUMS:
|
||||
React-runtimescheduler: 508ec4adf3a3a5ffb7b3d10d1f236a2a9022ce5a
|
||||
React-utils: 52afeb88f90c5a40fa42a145df7877595302f6cf
|
||||
ReactCommon: 41305560b33e9d8f059560e65a283d40c6885fa0
|
||||
RNReanimated: e4276a6afc57c02056daa5ea1afb41a5ec497d9b
|
||||
RNReanimated: 15c09dc3d57e26de3895d5306d283503c9eddeac
|
||||
RNSVG: cb24fb322de8c1ebf59904e7aca0447bb8dbed5a
|
||||
SocketRocket: f6c6249082c011e6de2de60ed641ef8bbe0cfac9
|
||||
Yoga: b734a95cb36e2b7e9e7b5733ce679a97e4f37da4
|
||||
|
||||
@@ -18,6 +18,7 @@ module.exports = {
|
||||
'RNSVGClipPathComponentDescriptor',
|
||||
'RNSVGDefsComponentDescriptor',
|
||||
'RNSVGFeColorMatrixComponentDescriptor',
|
||||
'RNSVGFeGaussianBlurComponentDescriptor',
|
||||
'RNSVGFilterComponentDescriptor',
|
||||
'RNSVGEllipseComponentDescriptor',
|
||||
'RNSVGForeignObjectComponentDescriptor',
|
||||
|
||||
@@ -25,6 +25,7 @@ import Marker from './elements/Marker';
|
||||
import ForeignObject from './elements/ForeignObject';
|
||||
import Filter from './elements/filters/Filter';
|
||||
import FeColorMatrix from './elements/filters/FeColorMatrix';
|
||||
import FeGaussianBlur from './elements/filters/FeGaussianBlur';
|
||||
|
||||
import {
|
||||
parse,
|
||||
@@ -71,6 +72,7 @@ import {
|
||||
RNSVGUse,
|
||||
RNSVGFilter,
|
||||
RNSVGFeColorMatrix,
|
||||
RNSVGFeGaussianBlur,
|
||||
} from './fabric';
|
||||
|
||||
export {
|
||||
@@ -109,6 +111,7 @@ export type { MarkerProps } from './elements/Marker';
|
||||
export type { ForeignObjectProps } from './elements/ForeignObject';
|
||||
export type { FilterProps } from './elements/filters/Filter';
|
||||
export type { FeColorMatrixProps } from './elements/filters/FeColorMatrix';
|
||||
export type { FeGaussianBlurProps } from './elements/filters/FeGaussianBlur';
|
||||
export type { FilterPrimitiveCommonProps } from './elements/filters/FilterPrimitive';
|
||||
|
||||
export * from './lib/extract/types';
|
||||
@@ -149,6 +152,7 @@ export {
|
||||
Shape,
|
||||
Filter,
|
||||
FeColorMatrix,
|
||||
FeGaussianBlur,
|
||||
RNSVGMarker,
|
||||
RNSVGMask,
|
||||
RNSVGPattern,
|
||||
@@ -173,6 +177,7 @@ export {
|
||||
RNSVGForeignObject,
|
||||
RNSVGFilter,
|
||||
RNSVGFeColorMatrix,
|
||||
RNSVGFeGaussianBlur,
|
||||
};
|
||||
|
||||
export type {
|
||||
|
||||
40
src/elements/filters/FeGaussianBlur.tsx
Normal file
40
src/elements/filters/FeGaussianBlur.tsx
Normal file
@@ -0,0 +1,40 @@
|
||||
import * as React from 'react';
|
||||
import { NativeMethods } from 'react-native';
|
||||
import RNSVGFeGaussianBlur from '../../fabric/FeGaussianBlurNativeComponent';
|
||||
import {
|
||||
extractFeGaussianBlur,
|
||||
extractFilter,
|
||||
} from '../../lib/extract/extractFilter';
|
||||
import { FilterEdgeMode, NumberProp } from '../../lib/extract/types';
|
||||
import FilterPrimitive from './FilterPrimitive';
|
||||
|
||||
export interface FeGaussianBlurProps {
|
||||
in?: string;
|
||||
stdDeviation?: NumberProp;
|
||||
// edgeMode is hard to implement and not supported by any
|
||||
// browser except safari, so it's not implemented for now
|
||||
// https://caniuse.com/mdn-api_svgfegaussianblurelement_edgemode
|
||||
edgeMode?: FilterEdgeMode;
|
||||
}
|
||||
|
||||
export default class FeGaussianBlur extends FilterPrimitive<FeGaussianBlurProps> {
|
||||
static displayName = 'FeGaussianBlur';
|
||||
|
||||
static defaultProps = {
|
||||
...this.defaultPrimitiveProps,
|
||||
stdDeviation: 0,
|
||||
edgeMode: 'none',
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<RNSVGFeGaussianBlur
|
||||
ref={(ref) =>
|
||||
this.refMethod(ref as (FeGaussianBlur & NativeMethods) | null)
|
||||
}
|
||||
{...extractFilter(this.props)}
|
||||
{...extractFeGaussianBlur(this.props)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
25
src/fabric/FeGaussianBlurNativeComponent.ts
Normal file
25
src/fabric/FeGaussianBlurNativeComponent.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
|
||||
import type { ViewProps } from './utils';
|
||||
|
||||
import { NumberProp } from '../lib/extract/types';
|
||||
import type { UnsafeMixed } from './codegenUtils';
|
||||
import { Float, WithDefault } from 'react-native/Libraries/Types/CodegenTypes';
|
||||
|
||||
type FilterEdgeMode = 'duplicate' | 'wrap' | 'none';
|
||||
|
||||
interface FilterPrimitiveCommonProps {
|
||||
x?: UnsafeMixed<NumberProp>;
|
||||
y?: UnsafeMixed<NumberProp>;
|
||||
width?: UnsafeMixed<NumberProp>;
|
||||
height?: UnsafeMixed<NumberProp>;
|
||||
result?: string;
|
||||
}
|
||||
|
||||
export interface NativeProps extends ViewProps, FilterPrimitiveCommonProps {
|
||||
in1?: string;
|
||||
stdDeviationX?: Float;
|
||||
stdDeviationY?: Float;
|
||||
edgeMode?: WithDefault<FilterEdgeMode, 'none'>;
|
||||
}
|
||||
|
||||
export default codegenNativeComponent<NativeProps>('RNSVGFeGaussianBlur');
|
||||
@@ -22,6 +22,7 @@ import RNSVGTSpan from './TSpanNativeComponent';
|
||||
import RNSVGUse from './UseNativeComponent';
|
||||
import RNSVGFilter from './FilterNativeComponent';
|
||||
import RNSVGFeColorMatrix from './FeColorMatrixNativeComponent';
|
||||
import RNSVGFeGaussianBlur from './FeGaussianBlurNativeComponent';
|
||||
|
||||
export {
|
||||
RNSVGCircle,
|
||||
@@ -48,4 +49,5 @@ export {
|
||||
RNSVGUse,
|
||||
RNSVGFilter,
|
||||
RNSVGFeColorMatrix,
|
||||
RNSVGFeGaussianBlur,
|
||||
};
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { FilterPrimitiveCommonProps } from '../elements/filters/FilterPrimitive';
|
||||
import { FeColorMatrixProps } from '../index';
|
||||
import { FeColorMatrixProps, FeGaussianBlurProps } from '../index';
|
||||
|
||||
export type FilterElement = ({ name: 'feColorMatrix' } & FeColorMatrixProps) &
|
||||
export type FilterElement = (
|
||||
| ({ name: 'feColorMatrix' } & FeColorMatrixProps)
|
||||
| ({ name: 'feGaussianBlur' } & FeGaussianBlurProps)
|
||||
) &
|
||||
FilterPrimitiveCommonProps;
|
||||
|
||||
export type Filters = Array<FilterElement>;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { FeColorMatrixProps as FeColorMatrixComponentProps } from '../../elements/filters/FeColorMatrix';
|
||||
import { FeGaussianBlurProps as FeGaussianBlurComponentProps } from '../../elements/filters/FeGaussianBlur';
|
||||
import { NativeProps as FeColorMatrixNativeProps } from '../../fabric/FeColorMatrixNativeComponent';
|
||||
import { NativeProps as FeGaussianBlurNativeProps } from '../../fabric/FeGaussianBlurNativeComponent';
|
||||
import { NumberProp } from './types';
|
||||
|
||||
const spaceReg = /\s+/;
|
||||
@@ -53,3 +55,32 @@ export const extractFeColorMatrix = (
|
||||
|
||||
return extracted;
|
||||
};
|
||||
|
||||
export const extractFeGaussianBlur = (
|
||||
props: FeGaussianBlurComponentProps
|
||||
): FeGaussianBlurNativeProps => {
|
||||
const extracted: FeGaussianBlurNativeProps = {};
|
||||
|
||||
if (props.in) {
|
||||
extracted.in1 = props.in;
|
||||
}
|
||||
if (
|
||||
typeof props.stdDeviation === 'string' &&
|
||||
props.stdDeviation.match(spaceReg)
|
||||
) {
|
||||
const stdDeviation = props.stdDeviation.split(spaceReg);
|
||||
extracted.stdDeviationX = Number(stdDeviation[0]) || 0;
|
||||
extracted.stdDeviationY = Number(stdDeviation[1]) || 0;
|
||||
} else if (
|
||||
typeof props.stdDeviation === 'number' ||
|
||||
(typeof props.stdDeviation === 'string' &&
|
||||
!props.stdDeviation.match(spaceReg))
|
||||
) {
|
||||
extracted.stdDeviationX = Number(props.stdDeviation) || 0;
|
||||
extracted.stdDeviationY = Number(props.stdDeviation) || 0;
|
||||
}
|
||||
if (props.edgeMode) {
|
||||
extracted.edgeMode = props.edgeMode;
|
||||
}
|
||||
return extracted;
|
||||
};
|
||||
|
||||
@@ -27,6 +27,7 @@ import Mask from './elements/Mask';
|
||||
import Marker from './elements/Marker';
|
||||
import Filter from './elements/filters/Filter';
|
||||
import FeColorMatrix from './elements/filters/FeColorMatrix';
|
||||
import FeGaussianBlur from './elements/filters/FeGaussianBlur';
|
||||
|
||||
export const tags: { [tag: string]: ComponentType } = {
|
||||
svg: Svg,
|
||||
@@ -54,6 +55,7 @@ export const tags: { [tag: string]: ComponentType } = {
|
||||
marker: Marker,
|
||||
filter: Filter,
|
||||
feColorMatrix: FeColorMatrix,
|
||||
feGaussianBlur: FeGaussianBlur,
|
||||
};
|
||||
|
||||
function missingTag() {
|
||||
|
||||
Reference in New Issue
Block a user