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:
Jakub Grzywacz
2024-07-25 11:46:45 +02:00
committed by GitHub
parent ba7d77548f
commit 44254df9fb
27 changed files with 624 additions and 13 deletions

View File

@@ -1260,6 +1260,7 @@ Filter effects are a way of processing an elements rendering before it is dis
Currently supported\* filters are:
- FeColorMatrix
- FeGaussianBlur
\*_More filters are coming soon_

View File

@@ -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);
}
}

View File

@@ -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() {

View File

@@ -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(

View File

@@ -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);
}
}
}

View File

@@ -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);
}

View File

@@ -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,

View File

@@ -160,8 +160,6 @@ using namespace facebook::react;
[filter setValue:inputImage forKey:@"inputImage"];
return [filter valueForKey:@"outputImage"];
return nil;
}
#ifdef RCT_NEW_ARCH_ENABLED

View 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

View 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

View File

@@ -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"

View File

@@ -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(

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,5 @@
#import "RNSVGFilterPrimitiveManager.h"
@interface RNSVGFeGaussianBlurManager : RNSVGFilterPrimitiveManager
@end

View 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

View 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};

View File

@@ -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};

View File

@@ -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

View File

@@ -18,6 +18,7 @@ module.exports = {
'RNSVGClipPathComponentDescriptor',
'RNSVGDefsComponentDescriptor',
'RNSVGFeColorMatrixComponentDescriptor',
'RNSVGFeGaussianBlurComponentDescriptor',
'RNSVGFilterComponentDescriptor',
'RNSVGEllipseComponentDescriptor',
'RNSVGForeignObjectComponentDescriptor',

View File

@@ -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 {

View 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)}
/>
);
}
}

View 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');

View File

@@ -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,
};

View File

@@ -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>;

View File

@@ -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;
};

View File

@@ -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() {