Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add FeGaussianBlur filter #2352

Merged
merged 14 commits into from
Jul 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions USAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -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_

Expand Down
80 changes: 80 additions & 0 deletions android/src/main/java/com/horcrux/svg/FeGaussianBlurView.java
Original file line number Diff line number Diff line change
@@ -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;
jakex7 marked this conversation as resolved.
Show resolved Hide resolved
if (stdDeviation <= 0) return bitmap;
final float maxRadius = 25.0f;
jakex7 marked this conversation as resolved.
Show resolved Hide resolved
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));
jakex7 marked this conversation as resolved.
Show resolved Hide resolved

// 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);
}
}
60 changes: 60 additions & 0 deletions android/src/main/java/com/horcrux/svg/RenderableViewManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@
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;
Expand Down Expand Up @@ -584,6 +586,7 @@ protected enum SVGClass {
RNSVGMask,
RNSVGFilter,
RNSVGFeColorMatrix,
RNSVGFeGaussianBlur,
RNSVGMarker,
RNSVGForeignObject,
}
Expand Down Expand Up @@ -632,6 +635,8 @@ protected VirtualView createViewInstance(@Nonnull ThemedReactContext reactContex
return new FilterView(reactContext);
case RNSVGFeColorMatrix:
return new FeColorMatrixView(reactContext);
case RNSVGFeGaussianBlur:
return new FeGaussianBlurView(reactContext);
case RNSVGMarker:
return new MarkerView(reactContext);
case RNSVGForeignObject:
Expand Down Expand Up @@ -1387,6 +1392,61 @@ public void setValues(FeColorMatrixView node, @Nullable ReadableArray values) {
}
}

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) {
jakex7 marked this conversation as resolved.
Show resolved Hide resolved
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() {
Expand Down
9 changes: 9 additions & 0 deletions android/src/main/java/com/horcrux/svg/SvgPackage.java
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,15 @@ public NativeModule get() {
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(
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
Original file line number Diff line number Diff line change
@@ -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,
Expand Down
2 changes: 0 additions & 2 deletions apple/Filters/RNSVGFeColorMatrix.mm
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,6 @@ - (CIImage *)applyFilter:(NSMutableDictionary<NSString *, CIImage *> *)results p
[filter setValue:inputImage forKey:@"inputImage"];

return [filter valueForKey:@"outputImage"];

return nil;
}

#ifdef RCT_NEW_ARCH_ENABLED
Expand Down
11 changes: 11 additions & 0 deletions apple/Filters/RNSVGFeGaussianBlur.h
Original file line number Diff line number Diff line change
@@ -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
Loading
Loading