mirror of
https://github.com/zoriya/react-native-svg.git
synced 2025-12-05 22:56:11 +00:00
feat: FeComposite filter (#2433)
# Summary <img width="324" alt="image" src="https://github.com/user-attachments/assets/0a9b4a56-d093-49f7-aacd-c198ee00f256"> ## Test Plan Examples app -> Filters -> FeComposite ## Compatibility | OS | Implemented | | ------- | :---------: | | iOS | ✅ | | macOS | ❌* | | Android | ✅ | | Web | ✅ | _*_ macOS isn't working as: * `CGBitmapContextCreateImage` always returns null * FeFlood isn't aligned properly (will be fixed in the following PR)
This commit is contained in:
@@ -12,13 +12,18 @@ Pod::Spec.new do |s|
|
||||
s.homepage = package['homepage']
|
||||
s.authors = 'Horcrux Chen'
|
||||
s.source = { :git => 'https://github.com/react-native-community/react-native-svg.git', :tag => "v#{s.version}" }
|
||||
s.source_files = 'apple/**/*.{h,m,mm}'
|
||||
s.source_files = 'apple/**/*.{h,m,mm,metal}'
|
||||
s.ios.exclude_files = '**/*.macos.{h,m,mm}'
|
||||
s.tvos.exclude_files = '**/*.macos.{h,m,mm}'
|
||||
s.visionos.exclude_files = '**/*.macos.{h,m,mm}' if s.respond_to?(:visionos)
|
||||
s.osx.exclude_files = '**/*.ios.{h,m,mm}'
|
||||
s.requires_arc = true
|
||||
s.requires_arc = true
|
||||
s.platforms = { :osx => "10.14", :ios => "12.4", :tvos => "12.4", :visionos => "1.0" }
|
||||
|
||||
s.osx.resource_bundles = {'RNSVGFilters' => ['apple/**/*.macosx.metallib']}
|
||||
s.ios.resource_bundles = {'RNSVGFilters' => ['apple/**/*.iphoneos.metallib']}
|
||||
s.tvos.resource_bundles = {'RNSVGFilters' => ['apple/**/*.appletvos.metallib']}
|
||||
s.visionos.resource_bundles = {'RNSVGFilters' => ['apple/**/*.xros.metallib']}
|
||||
|
||||
if fabric_enabled
|
||||
install_modules_dependencies(s)
|
||||
|
||||
132
android/src/main/java/com/horcrux/svg/FeCompositeView.java
Normal file
132
android/src/main/java/com/horcrux/svg/FeCompositeView.java
Normal file
@@ -0,0 +1,132 @@
|
||||
package com.horcrux.svg;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffXfermode;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import java.util.HashMap;
|
||||
|
||||
@SuppressLint("ViewConstructor")
|
||||
class FeCompositeView extends FilterPrimitiveView {
|
||||
String mIn1;
|
||||
String mIn2;
|
||||
float mK1;
|
||||
float mK2;
|
||||
float mK3;
|
||||
float mK4;
|
||||
FilterProperties.FeCompositeOperator mOperator;
|
||||
|
||||
public FeCompositeView(ReactContext reactContext) {
|
||||
super(reactContext);
|
||||
}
|
||||
|
||||
public void setIn1(String in1) {
|
||||
this.mIn1 = in1;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setIn2(String in2) {
|
||||
this.mIn2 = in2;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setK1(Float value) {
|
||||
this.mK1 = value;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setK2(Float value) {
|
||||
this.mK2 = value;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setK3(Float value) {
|
||||
this.mK3 = value;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setK4(Float value) {
|
||||
this.mK4 = value;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setOperator(String operator) {
|
||||
this.mOperator = FilterProperties.FeCompositeOperator.getEnum(operator);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bitmap applyFilter(HashMap<String, Bitmap> resultsMap, Bitmap prevResult) {
|
||||
Bitmap in1 = getSource(resultsMap, prevResult, this.mIn1);
|
||||
Bitmap in2 = getSource(resultsMap, prevResult, this.mIn2);
|
||||
Bitmap result = Bitmap.createBitmap(in1.getWidth(), in1.getHeight(), Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(result);
|
||||
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
canvas.drawBitmap(in1, 0, 0, paint);
|
||||
|
||||
switch (this.mOperator) {
|
||||
case OVER -> {
|
||||
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OVER));
|
||||
}
|
||||
case IN -> {
|
||||
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
|
||||
}
|
||||
case OUT -> {
|
||||
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
|
||||
}
|
||||
case ATOP -> {
|
||||
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP));
|
||||
}
|
||||
case XOR -> {
|
||||
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR));
|
||||
}
|
||||
case ARITHMETIC -> {
|
||||
// result = k1*i1*i2 + k2*i1 + k3*i2 + k4
|
||||
int nPixels = result.getWidth() * result.getHeight();
|
||||
int[] pixels1 = new int[nPixels];
|
||||
int[] pixels2 = new int[nPixels];
|
||||
result.getPixels(
|
||||
pixels1, 0, result.getWidth(), 0, 0, result.getWidth(), result.getHeight());
|
||||
|
||||
for (int i = 0; i < nPixels; i++) {
|
||||
int color1 = pixels1[i];
|
||||
int color2 = pixels2[i];
|
||||
|
||||
int r1 = (color1 >> 16) & 0xFF;
|
||||
int g1 = (color1 >> 8) & 0xFF;
|
||||
int b1 = color1 & 0xFF;
|
||||
int a1 = (color1 >>> 24);
|
||||
int r2 = (color2 >> 16) & 0xFF;
|
||||
int g2 = (color2 >> 8) & 0xFF;
|
||||
int b2 = color2 & 0xFF;
|
||||
int a2 = (color2 >>> 24);
|
||||
|
||||
int rResult = (int) (mK1 * r1 * r2 + mK2 * r1 + mK3 * r2 + mK4);
|
||||
int gResult = (int) (mK1 * g1 * g2 + mK2 * g1 + mK3 * g2 + mK4);
|
||||
int bResult = (int) (mK1 * b1 * b2 + mK2 * b1 + mK3 * b2 + mK4);
|
||||
int aResult = (int) (mK1 * a1 * a2 + mK2 * a1 + mK3 * a2 + mK4);
|
||||
|
||||
rResult = Math.min(255, Math.max(0, rResult));
|
||||
gResult = Math.min(255, Math.max(0, gResult));
|
||||
bResult = Math.min(255, Math.max(0, bResult));
|
||||
aResult = Math.min(255, Math.max(0, aResult));
|
||||
|
||||
int pixel = (aResult << 24) | (rResult << 16) | (gResult << 8) | bResult;
|
||||
pixels1[i] = pixel;
|
||||
}
|
||||
|
||||
result.setPixels(
|
||||
pixels1, 0, result.getWidth(), 0, 0, result.getWidth(), result.getHeight());
|
||||
}
|
||||
}
|
||||
|
||||
if (this.mOperator != FilterProperties.FeCompositeOperator.ARITHMETIC) {
|
||||
canvas.drawBitmap(in2, 0, 0, paint);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -144,4 +144,41 @@ class FilterProperties {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
enum FeCompositeOperator {
|
||||
OVER("over"),
|
||||
IN("in"),
|
||||
OUT("out"),
|
||||
ATOP("atop"),
|
||||
XOR("xor"),
|
||||
ARITHMETIC("arithmetic"),
|
||||
;
|
||||
|
||||
private final String type;
|
||||
|
||||
FeCompositeOperator(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
static FeCompositeOperator getEnum(String strVal) {
|
||||
if (!typeToEnum.containsKey(strVal)) {
|
||||
throw new IllegalArgumentException("Unknown String Value: " + strVal);
|
||||
}
|
||||
return typeToEnum.get(strVal);
|
||||
}
|
||||
|
||||
private static final Map<String, FeCompositeOperator> typeToEnum = new HashMap<>();
|
||||
|
||||
static {
|
||||
for (final FeCompositeOperator en : FeCompositeOperator.values()) {
|
||||
typeToEnum.put(en.type, en);
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String toString() {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,6 +107,8 @@ import com.facebook.react.viewmanagers.RNSVGFeBlendManagerDelegate;
|
||||
import com.facebook.react.viewmanagers.RNSVGFeBlendManagerInterface;
|
||||
import com.facebook.react.viewmanagers.RNSVGFeColorMatrixManagerDelegate;
|
||||
import com.facebook.react.viewmanagers.RNSVGFeColorMatrixManagerInterface;
|
||||
import com.facebook.react.viewmanagers.RNSVGFeCompositeManagerDelegate;
|
||||
import com.facebook.react.viewmanagers.RNSVGFeCompositeManagerInterface;
|
||||
import com.facebook.react.viewmanagers.RNSVGFeFloodManagerDelegate;
|
||||
import com.facebook.react.viewmanagers.RNSVGFeFloodManagerInterface;
|
||||
import com.facebook.react.viewmanagers.RNSVGFeGaussianBlurManagerDelegate;
|
||||
@@ -595,6 +597,7 @@ class VirtualViewManager<V extends VirtualView> extends ViewGroupManager<Virtual
|
||||
RNSVGFilter,
|
||||
RNSVGFeBlend,
|
||||
RNSVGFeColorMatrix,
|
||||
RNSVGFeComposite,
|
||||
RNSVGFeFlood,
|
||||
RNSVGFeGaussianBlur,
|
||||
RNSVGFeMerge,
|
||||
@@ -649,6 +652,8 @@ class VirtualViewManager<V extends VirtualView> extends ViewGroupManager<Virtual
|
||||
return new FeBlendView(reactContext);
|
||||
case RNSVGFeColorMatrix:
|
||||
return new FeColorMatrixView(reactContext);
|
||||
case RNSVGFeComposite:
|
||||
return new FeCompositeView(reactContext);
|
||||
case RNSVGFeFlood:
|
||||
return new FeFloodView(reactContext);
|
||||
case RNSVGFeGaussianBlur:
|
||||
@@ -1640,6 +1645,51 @@ class RenderableViewManager<T extends RenderableView> extends VirtualViewManager
|
||||
}
|
||||
}
|
||||
|
||||
static class FeCompositeManager extends FilterPrimitiveManager<FeCompositeView>
|
||||
implements RNSVGFeCompositeManagerInterface<FeCompositeView> {
|
||||
FeCompositeManager() {
|
||||
super(SVGClass.RNSVGFeComposite);
|
||||
mDelegate = new RNSVGFeCompositeManagerDelegate(this);
|
||||
}
|
||||
|
||||
public static final String REACT_CLASS = "RNSVGFeComposite";
|
||||
|
||||
@ReactProp(name = "in1")
|
||||
public void setIn1(FeCompositeView node, String in1) {
|
||||
node.setIn1(in1);
|
||||
}
|
||||
|
||||
@ReactProp(name = "in2")
|
||||
public void setIn2(FeCompositeView node, String in2) {
|
||||
node.setIn2(in2);
|
||||
}
|
||||
|
||||
@ReactProp(name = "operator1")
|
||||
public void setOperator1(FeCompositeView node, String operator) {
|
||||
node.setOperator(operator);
|
||||
}
|
||||
|
||||
@ReactProp(name = "k1")
|
||||
public void setK1(FeCompositeView node, float value) {
|
||||
node.setK1(value);
|
||||
}
|
||||
|
||||
@ReactProp(name = "k2")
|
||||
public void setK2(FeCompositeView node, float value) {
|
||||
node.setK2(value);
|
||||
}
|
||||
|
||||
@ReactProp(name = "k3")
|
||||
public void setK3(FeCompositeView node, float value) {
|
||||
node.setK3(value);
|
||||
}
|
||||
|
||||
@ReactProp(name = "k4")
|
||||
public void setK4(FeCompositeView node, float value) {
|
||||
node.setK4(value);
|
||||
}
|
||||
}
|
||||
|
||||
static class FeFloodManager extends FilterPrimitiveManager<FeFloodView>
|
||||
implements RNSVGFeFloodManagerInterface<FeFloodView> {
|
||||
FeFloodManager() {
|
||||
|
||||
@@ -232,6 +232,15 @@ public class SvgPackage extends TurboReactPackage implements ViewManagerOnDemand
|
||||
return new FeColorMatrixManager();
|
||||
}
|
||||
}));
|
||||
specs.put(
|
||||
FeCompositeManager.REACT_CLASS,
|
||||
ModuleSpec.viewManagerSpec(
|
||||
new Provider<NativeModule>() {
|
||||
@Override
|
||||
public NativeModule get() {
|
||||
return new FeCompositeManager();
|
||||
}
|
||||
}));
|
||||
specs.put(
|
||||
FeFloodManager.REACT_CLASS,
|
||||
ModuleSpec.viewManagerSpec(
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* 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 RNSVGFeCompositeManagerDelegate<T extends View, U extends BaseViewManagerInterface<T> & RNSVGFeCompositeManagerInterface<T>> extends BaseViewManagerDelegate<T, U> {
|
||||
public RNSVGFeCompositeManagerDelegate(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 "in2":
|
||||
mViewManager.setIn2(view, value == null ? null : (String) value);
|
||||
break;
|
||||
case "operator1":
|
||||
mViewManager.setOperator1(view, (String) value);
|
||||
break;
|
||||
case "k1":
|
||||
mViewManager.setK1(view, value == null ? 0f : ((Double) value).floatValue());
|
||||
break;
|
||||
case "k2":
|
||||
mViewManager.setK2(view, value == null ? 0f : ((Double) value).floatValue());
|
||||
break;
|
||||
case "k3":
|
||||
mViewManager.setK3(view, value == null ? 0f : ((Double) value).floatValue());
|
||||
break;
|
||||
case "k4":
|
||||
mViewManager.setK4(view, value == null ? 0f : ((Double) value).floatValue());
|
||||
break;
|
||||
default:
|
||||
super.setProperty(view, propName, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* 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 RNSVGFeCompositeManagerInterface<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 setIn2(T view, @Nullable String value);
|
||||
void setOperator1(T view, @Nullable String value);
|
||||
void setK1(T view, float value);
|
||||
void setK2(T view, float value);
|
||||
void setK3(T view, float value);
|
||||
void setK4(T view, float value);
|
||||
}
|
||||
BIN
apple/Filters/MetalCI/RNSVGArithmeticFilter.appletvos.air
Normal file
BIN
apple/Filters/MetalCI/RNSVGArithmeticFilter.appletvos.air
Normal file
Binary file not shown.
BIN
apple/Filters/MetalCI/RNSVGArithmeticFilter.appletvos.metallib
Normal file
BIN
apple/Filters/MetalCI/RNSVGArithmeticFilter.appletvos.metallib
Normal file
Binary file not shown.
11
apple/Filters/MetalCI/RNSVGArithmeticFilter.h
Normal file
11
apple/Filters/MetalCI/RNSVGArithmeticFilter.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#import "RNSVGCustomFilter.h"
|
||||
|
||||
@interface RNSVGArithmeticFilter : RNSVGCustomFilter {
|
||||
CIImage *inputImage2;
|
||||
NSNumber *inputK1;
|
||||
NSNumber *inputK2;
|
||||
NSNumber *inputK3;
|
||||
NSNumber *inputK4;
|
||||
}
|
||||
|
||||
@end
|
||||
BIN
apple/Filters/MetalCI/RNSVGArithmeticFilter.iphoneos.air
Normal file
BIN
apple/Filters/MetalCI/RNSVGArithmeticFilter.iphoneos.air
Normal file
Binary file not shown.
BIN
apple/Filters/MetalCI/RNSVGArithmeticFilter.iphoneos.metallib
Normal file
BIN
apple/Filters/MetalCI/RNSVGArithmeticFilter.iphoneos.metallib
Normal file
Binary file not shown.
BIN
apple/Filters/MetalCI/RNSVGArithmeticFilter.macosx.air
Normal file
BIN
apple/Filters/MetalCI/RNSVGArithmeticFilter.macosx.air
Normal file
Binary file not shown.
BIN
apple/Filters/MetalCI/RNSVGArithmeticFilter.macosx.metallib
Normal file
BIN
apple/Filters/MetalCI/RNSVGArithmeticFilter.macosx.metallib
Normal file
Binary file not shown.
16
apple/Filters/MetalCI/RNSVGArithmeticFilter.metal
Normal file
16
apple/Filters/MetalCI/RNSVGArithmeticFilter.metal
Normal file
@@ -0,0 +1,16 @@
|
||||
#include <metal_stdlib>
|
||||
using namespace metal;
|
||||
#include <CoreImage/CoreImage.h>
|
||||
|
||||
|
||||
extern "C" float4 RNSVGArithmeticFilter(coreimage::sample_t in1, coreimage::sample_t in2, float k1, float k2, float k3, float k4)
|
||||
{
|
||||
float4 arithmeticResult;
|
||||
arithmeticResult.rgb = k1 * in1.rgb * in2.rgb + k2 * in1.rgb + k3 * in2.rgb + k4;
|
||||
arithmeticResult.a = k1 * in1.a * in2.a + k2 * in1.a + k3 * in2.a + k4;
|
||||
|
||||
arithmeticResult.rgb = clamp(arithmeticResult.rgb, 0.0, 1.0);
|
||||
arithmeticResult.a = clamp(arithmeticResult.a, 0.0, 1.0);
|
||||
|
||||
return arithmeticResult;
|
||||
}
|
||||
66
apple/Filters/MetalCI/RNSVGArithmeticFilter.mm
Normal file
66
apple/Filters/MetalCI/RNSVGArithmeticFilter.mm
Normal file
@@ -0,0 +1,66 @@
|
||||
#import "RNSVGArithmeticFilter.h"
|
||||
|
||||
static CIColorKernel *arithmeticFilter = nil;
|
||||
|
||||
@implementation RNSVGArithmeticFilter
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if (arithmeticFilter == nil) {
|
||||
arithmeticFilter = [super getWithName:@"RNSVGArithmeticFilter"];
|
||||
}
|
||||
return [super init];
|
||||
}
|
||||
|
||||
- (NSDictionary *)customAttributes
|
||||
{
|
||||
return @{
|
||||
@"inputImage1" : @{
|
||||
kCIAttributeIdentity : @0,
|
||||
kCIAttributeClass : @"CIImage",
|
||||
kCIAttributeDisplayName : @"in1",
|
||||
kCIAttributeType : kCIAttributeTypeImage
|
||||
},
|
||||
@"inputImage2" : @{
|
||||
kCIAttributeIdentity : @0,
|
||||
kCIAttributeClass : @"CIImage",
|
||||
kCIAttributeDisplayName : @"in2",
|
||||
kCIAttributeType : kCIAttributeTypeImage
|
||||
},
|
||||
@"inputK1" : @{
|
||||
kCIAttributeIdentity : @0,
|
||||
kCIAttributeClass : @"NSNumber",
|
||||
kCIAttributeDisplayName : @"k1",
|
||||
kCIAttributeType : kCIAttributeTypeScalar
|
||||
},
|
||||
@"inputK2" : @{
|
||||
kCIAttributeIdentity : @0,
|
||||
kCIAttributeClass : @"NSNumber",
|
||||
kCIAttributeDisplayName : @"k2",
|
||||
kCIAttributeType : kCIAttributeTypeScalar
|
||||
},
|
||||
@"inputK3" : @{
|
||||
kCIAttributeIdentity : @0,
|
||||
kCIAttributeClass : @"NSNumber",
|
||||
kCIAttributeDisplayName : @"k3",
|
||||
kCIAttributeType : kCIAttributeTypeScalar
|
||||
},
|
||||
@"inputK4" : @{
|
||||
kCIAttributeIdentity : @0,
|
||||
kCIAttributeClass : @"NSNumber",
|
||||
kCIAttributeDisplayName : @"k4",
|
||||
kCIAttributeType : kCIAttributeTypeScalar
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
- (CIImage *)outputImage
|
||||
{
|
||||
CISampler *in1 = [CISampler samplerWithImage:inputImage1];
|
||||
CISampler *in2 = [CISampler samplerWithImage:inputImage2];
|
||||
|
||||
return [arithmeticFilter applyWithExtent:inputImage1.extent
|
||||
arguments:@[ in1, in2, inputK1, inputK2, inputK3, inputK4 ]];
|
||||
}
|
||||
|
||||
@end
|
||||
BIN
apple/Filters/MetalCI/RNSVGArithmeticFilter.xros.air
Normal file
BIN
apple/Filters/MetalCI/RNSVGArithmeticFilter.xros.air
Normal file
Binary file not shown.
BIN
apple/Filters/MetalCI/RNSVGArithmeticFilter.xros.metallib
Normal file
BIN
apple/Filters/MetalCI/RNSVGArithmeticFilter.xros.metallib
Normal file
Binary file not shown.
BIN
apple/Filters/MetalCI/RNSVGCompositeXor.appletvos.air
Normal file
BIN
apple/Filters/MetalCI/RNSVGCompositeXor.appletvos.air
Normal file
Binary file not shown.
BIN
apple/Filters/MetalCI/RNSVGCompositeXor.appletvos.metallib
Normal file
BIN
apple/Filters/MetalCI/RNSVGCompositeXor.appletvos.metallib
Normal file
Binary file not shown.
7
apple/Filters/MetalCI/RNSVGCompositeXor.h
Normal file
7
apple/Filters/MetalCI/RNSVGCompositeXor.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#import "RNSVGCustomFilter.h"
|
||||
|
||||
@interface RNSVGCompositeXor : RNSVGCustomFilter {
|
||||
CIImage *inputImage2;
|
||||
}
|
||||
|
||||
@end
|
||||
BIN
apple/Filters/MetalCI/RNSVGCompositeXor.iphoneos.air
Normal file
BIN
apple/Filters/MetalCI/RNSVGCompositeXor.iphoneos.air
Normal file
Binary file not shown.
BIN
apple/Filters/MetalCI/RNSVGCompositeXor.iphoneos.metallib
Normal file
BIN
apple/Filters/MetalCI/RNSVGCompositeXor.iphoneos.metallib
Normal file
Binary file not shown.
BIN
apple/Filters/MetalCI/RNSVGCompositeXor.macosx.air
Normal file
BIN
apple/Filters/MetalCI/RNSVGCompositeXor.macosx.air
Normal file
Binary file not shown.
BIN
apple/Filters/MetalCI/RNSVGCompositeXor.macosx.metallib
Normal file
BIN
apple/Filters/MetalCI/RNSVGCompositeXor.macosx.metallib
Normal file
Binary file not shown.
13
apple/Filters/MetalCI/RNSVGCompositeXor.metal
Normal file
13
apple/Filters/MetalCI/RNSVGCompositeXor.metal
Normal file
@@ -0,0 +1,13 @@
|
||||
#include <metal_stdlib>
|
||||
using namespace metal;
|
||||
#include <CoreImage/CoreImage.h>
|
||||
|
||||
extern "C" float4 RNSVGCompositeXor(coreimage::sample_t in1, coreimage::sample_t in2)
|
||||
{
|
||||
float4 result;
|
||||
|
||||
result.rgb = in1.rgb * (1.0 - in2.a) + in2.rgb * (1.0 - in1.a);
|
||||
result.a = in1.a + in2.a - 2.0 * in1.a * in2.a;
|
||||
|
||||
return result;
|
||||
}
|
||||
41
apple/Filters/MetalCI/RNSVGCompositeXor.mm
Normal file
41
apple/Filters/MetalCI/RNSVGCompositeXor.mm
Normal file
@@ -0,0 +1,41 @@
|
||||
#import "RNSVGCompositeXor.h"
|
||||
|
||||
static CIColorKernel *compositeXor = nil;
|
||||
|
||||
@implementation RNSVGCompositeXor
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if (compositeXor == nil) {
|
||||
compositeXor = [super getWithName:@"RNSVGCompositeXor"];
|
||||
}
|
||||
return [super init];
|
||||
}
|
||||
|
||||
- (NSDictionary *)customAttributes
|
||||
{
|
||||
return @{
|
||||
@"inputImage1" : @{
|
||||
kCIAttributeIdentity : @0,
|
||||
kCIAttributeClass : @"CIImage",
|
||||
kCIAttributeDisplayName : @"in1",
|
||||
kCIAttributeType : kCIAttributeTypeImage
|
||||
},
|
||||
@"inputImage2" : @{
|
||||
kCIAttributeIdentity : @0,
|
||||
kCIAttributeClass : @"CIImage",
|
||||
kCIAttributeDisplayName : @"in2",
|
||||
kCIAttributeType : kCIAttributeTypeImage
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
- (CIImage *)outputImage
|
||||
{
|
||||
CISampler *in1 = [CISampler samplerWithImage:inputImage1];
|
||||
CISampler *in2 = [CISampler samplerWithImage:inputImage2];
|
||||
|
||||
return [compositeXor applyWithExtent:inputImage1.extent arguments:@[ in1, in2 ]];
|
||||
}
|
||||
|
||||
@end
|
||||
BIN
apple/Filters/MetalCI/RNSVGCompositeXor.xros.air
Normal file
BIN
apple/Filters/MetalCI/RNSVGCompositeXor.xros.air
Normal file
Binary file not shown.
BIN
apple/Filters/MetalCI/RNSVGCompositeXor.xros.metallib
Normal file
BIN
apple/Filters/MetalCI/RNSVGCompositeXor.xros.metallib
Normal file
Binary file not shown.
9
apple/Filters/MetalCI/RNSVGCustomFilter.h
Normal file
9
apple/Filters/MetalCI/RNSVGCustomFilter.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#import <CoreImage/CoreImage.h>
|
||||
|
||||
@interface RNSVGCustomFilter : CIFilter {
|
||||
CIImage *inputImage1;
|
||||
}
|
||||
|
||||
- (CIColorKernel *)getWithName:(NSString *)name;
|
||||
|
||||
@end
|
||||
35
apple/Filters/MetalCI/RNSVGCustomFilter.mm
Normal file
35
apple/Filters/MetalCI/RNSVGCustomFilter.mm
Normal file
@@ -0,0 +1,35 @@
|
||||
#import "RNSVGCustomFilter.h"
|
||||
|
||||
#if TARGET_OS_OSX
|
||||
#define extension @"macosx.metallib"
|
||||
#elif TARGET_OS_IOS
|
||||
#define extension @"iphoneos.metallib"
|
||||
#elif TARGET_OS_TV
|
||||
#define extension @"tvos.metallib"
|
||||
#elif TARGET_OS_VISION
|
||||
#define extension @"xros.metallib"
|
||||
#endif
|
||||
|
||||
@implementation RNSVGCustomFilter
|
||||
|
||||
- (CIColorKernel *)getWithName:(NSString *)name
|
||||
{
|
||||
NSBundle *frameworkBundle = [NSBundle bundleForClass:[self class]];
|
||||
NSURL *bundleUrl = [frameworkBundle.resourceURL URLByAppendingPathComponent:@"RNSVGFilters.bundle"];
|
||||
NSBundle *bundle = [NSBundle bundleWithURL:bundleUrl];
|
||||
NSURL *url = [bundle URLForResource:name withExtension:extension];
|
||||
|
||||
if (url != nil) {
|
||||
NSError *error = nil;
|
||||
NSData *data = [NSData dataWithContentsOfURL:url options:0 error:&error];
|
||||
|
||||
@try {
|
||||
return [CIColorKernel kernelWithFunctionName:name fromMetalLibraryData:data error:&error];
|
||||
} @catch (NSException *exception) {
|
||||
NSLog(@"RNSVG CustomFilter exception: %@", exception);
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
9
apple/Filters/RNSVGCompositeOperator.h
Normal file
9
apple/Filters/RNSVGCompositeOperator.h
Normal file
@@ -0,0 +1,9 @@
|
||||
typedef CF_ENUM(int32_t, RNSVGCompositeOperator) {
|
||||
SVG_FECOMPOSITE_OPERATOR_UNKNOWN,
|
||||
SVG_FECOMPOSITE_OPERATOR_OVER,
|
||||
SVG_FECOMPOSITE_OPERATOR_IN,
|
||||
SVG_FECOMPOSITE_OPERATOR_OUT,
|
||||
SVG_FECOMPOSITE_OPERATOR_ATOP,
|
||||
SVG_FECOMPOSITE_OPERATOR_XOR,
|
||||
SVG_FECOMPOSITE_OPERATOR_ARITHMETIC
|
||||
};
|
||||
16
apple/Filters/RNSVGFeComposite.h
Normal file
16
apple/Filters/RNSVGFeComposite.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#import "RNSVGArithmeticFilter.h"
|
||||
#import "RNSVGCompositeOperator.h"
|
||||
#import "RNSVGCompositeXor.h"
|
||||
#import "RNSVGFilterPrimitive.h"
|
||||
|
||||
@interface RNSVGFeComposite : RNSVGFilterPrimitive
|
||||
|
||||
@property (nonatomic, strong) NSString *in1;
|
||||
@property (nonatomic, strong) NSString *in2;
|
||||
@property (nonatomic, assign) RNSVGCompositeOperator operator1;
|
||||
@property (nonatomic, strong) NSNumber *k1;
|
||||
@property (nonatomic, strong) NSNumber *k2;
|
||||
@property (nonatomic, strong) NSNumber *k3;
|
||||
@property (nonatomic, strong) NSNumber *k4;
|
||||
|
||||
@end
|
||||
201
apple/Filters/RNSVGFeComposite.mm
Normal file
201
apple/Filters/RNSVGFeComposite.mm
Normal file
@@ -0,0 +1,201 @@
|
||||
#import "RNSVGFeComposite.h"
|
||||
#import "RNSVGArithmeticFilter.h"
|
||||
#import "RNSVGCompositeXor.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
|
||||
|
||||
static CIColorKernel *thresholdKernel;
|
||||
|
||||
@implementation RNSVGFeComposite
|
||||
|
||||
#ifdef RCT_NEW_ARCH_ENABLED
|
||||
using namespace facebook::react;
|
||||
|
||||
// Needed because of this: https://github.com/facebook/react-native/pull/37274
|
||||
+ (void)load
|
||||
{
|
||||
[super load];
|
||||
}
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame
|
||||
{
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
static const auto defaultProps = std::make_shared<const RNSVGFeCompositeProps>();
|
||||
_props = defaultProps;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - RCTComponentViewProtocol
|
||||
|
||||
+ (ComponentDescriptorProvider)componentDescriptorProvider
|
||||
{
|
||||
return concreteComponentDescriptorProvider<RNSVGFeCompositeComponentDescriptor>();
|
||||
}
|
||||
|
||||
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
||||
{
|
||||
const auto &newProps = static_cast<const RNSVGFeCompositeProps &>(*props);
|
||||
|
||||
self.in1 = RCTNSStringFromStringNilIfEmpty(newProps.in1);
|
||||
self.in2 = RCTNSStringFromStringNilIfEmpty(newProps.in2);
|
||||
self.k1 = [NSNumber numberWithFloat:newProps.k1];
|
||||
self.k2 = [NSNumber numberWithFloat:newProps.k2];
|
||||
self.k3 = [NSNumber numberWithFloat:newProps.k3];
|
||||
self.k4 = [NSNumber numberWithFloat:newProps.k4];
|
||||
self.operator1 = [RNSVGConvert RNSVGRNSVGCompositeOperatorFromCppEquivalent:newProps.operator1];
|
||||
|
||||
setCommonFilterProps(newProps, self);
|
||||
_props = std::static_pointer_cast<RNSVGFeCompositeProps const>(props);
|
||||
}
|
||||
|
||||
- (void)prepareForRecycle
|
||||
{
|
||||
[super prepareForRecycle];
|
||||
_in1 = nil;
|
||||
_in2 = nil;
|
||||
_k1 = nil;
|
||||
_k2 = nil;
|
||||
_k3 = nil;
|
||||
_k4 = nil;
|
||||
_operator1 = RNSVGCompositeOperator::SVG_FECOMPOSITE_OPERATOR_UNKNOWN;
|
||||
}
|
||||
#endif // RCT_NEW_ARCH_ENABLED
|
||||
|
||||
- (void)setIn1:(NSString *)in1
|
||||
{
|
||||
if ([in1 isEqualToString:_in1]) {
|
||||
return;
|
||||
}
|
||||
|
||||
_in1 = in1;
|
||||
[self invalidate];
|
||||
}
|
||||
|
||||
- (void)setIn2:(NSString *)in2
|
||||
{
|
||||
if ([in2 isEqualToString:_in2]) {
|
||||
return;
|
||||
}
|
||||
|
||||
_in2 = in2;
|
||||
[self invalidate];
|
||||
}
|
||||
|
||||
- (void)setK1:(NSNumber *)k1
|
||||
{
|
||||
if (k1 == _k1) {
|
||||
return;
|
||||
}
|
||||
|
||||
_k1 = k1;
|
||||
[self invalidate];
|
||||
}
|
||||
|
||||
- (void)setK2:(NSNumber *)k2
|
||||
{
|
||||
if (k2 == _k2) {
|
||||
return;
|
||||
}
|
||||
|
||||
_k2 = k2;
|
||||
[self invalidate];
|
||||
}
|
||||
|
||||
- (void)setK3:(NSNumber *)k3
|
||||
{
|
||||
if (k3 == _k3) {
|
||||
return;
|
||||
}
|
||||
|
||||
_k3 = k3;
|
||||
[self invalidate];
|
||||
}
|
||||
|
||||
- (void)setK4:(NSNumber *)k4
|
||||
{
|
||||
if (k4 == _k4) {
|
||||
return;
|
||||
}
|
||||
|
||||
_k4 = k4;
|
||||
[self invalidate];
|
||||
}
|
||||
|
||||
- (void)setOperator1:(RNSVGCompositeOperator)operator1
|
||||
{
|
||||
if (operator1 == _operator1) {
|
||||
return;
|
||||
}
|
||||
|
||||
_operator1 = operator1;
|
||||
[self invalidate];
|
||||
}
|
||||
|
||||
- (CIImage *)applyFilter:(NSMutableDictionary<NSString *, CIImage *> *)results previousFilterResult:(CIImage *)previous
|
||||
{
|
||||
CIImage *inResults1 = self.in1 ? [results objectForKey:self.in1] : nil;
|
||||
CIImage *inResults2 = self.in2 ? [results objectForKey:self.in2] : nil;
|
||||
CIImage *inputImage1 = inResults1 ? inResults1 : previous;
|
||||
CIImage *inputImage2 = inResults2 ? inResults2 : previous;
|
||||
|
||||
CIFilter *filter = nil;
|
||||
|
||||
switch (self.operator1) {
|
||||
case SVG_FECOMPOSITE_OPERATOR_OVER:
|
||||
filter = [CIFilter filterWithName:@"CISourceOverCompositing"];
|
||||
break;
|
||||
case SVG_FECOMPOSITE_OPERATOR_IN:
|
||||
filter = [CIFilter filterWithName:@"CISourceInCompositing"];
|
||||
break;
|
||||
case SVG_FECOMPOSITE_OPERATOR_OUT:
|
||||
filter = [CIFilter filterWithName:@"CISourceOutCompositing"];
|
||||
break;
|
||||
case SVG_FECOMPOSITE_OPERATOR_ATOP:
|
||||
filter = [CIFilter filterWithName:@"CISourceAtopCompositing"];
|
||||
break;
|
||||
case SVG_FECOMPOSITE_OPERATOR_XOR:
|
||||
filter = [[RNSVGCompositeXor alloc] init];
|
||||
break;
|
||||
case SVG_FECOMPOSITE_OPERATOR_ARITHMETIC:
|
||||
filter = [[RNSVGArithmeticFilter alloc] init];
|
||||
break;
|
||||
default:
|
||||
return nil;
|
||||
}
|
||||
|
||||
[filter setDefaults];
|
||||
|
||||
if (self.operator1 == SVG_FECOMPOSITE_OPERATOR_XOR) {
|
||||
[filter setValue:inputImage1 forKey:@"inputImage1"];
|
||||
[filter setValue:inputImage2 forKey:@"inputImage2"];
|
||||
} else if (self.operator1 == SVG_FECOMPOSITE_OPERATOR_ARITHMETIC) {
|
||||
[filter setValue:inputImage1 forKey:@"inputImage1"];
|
||||
[filter setValue:inputImage2 forKey:@"inputImage2"];
|
||||
[filter setValue:(self.k1 != nil ? self.k1 : 0) forKey:@"inputK1"];
|
||||
[filter setValue:(self.k2 != nil ? self.k2 : 0) forKey:@"inputK2"];
|
||||
[filter setValue:(self.k3 != nil ? self.k3 : 0) forKey:@"inputK3"];
|
||||
[filter setValue:(self.k4 != nil ? self.k4 : 0) forKey:@"inputK4"];
|
||||
} else {
|
||||
[filter setValue:inputImage1 forKey:@"inputImage"];
|
||||
[filter setValue:inputImage2 forKey:@"inputBackgroundImage"];
|
||||
}
|
||||
|
||||
return [filter valueForKey:@"outputImage"];
|
||||
}
|
||||
|
||||
#ifdef RCT_NEW_ARCH_ENABLED
|
||||
Class<RCTComponentViewProtocol> RNSVGFeCompositeCls(void)
|
||||
{
|
||||
return RNSVGFeComposite.class;
|
||||
}
|
||||
#endif // RCT_NEW_ARCH_ENABLED
|
||||
|
||||
@end
|
||||
@@ -13,6 +13,7 @@
|
||||
#import "RNSVGBlendMode.h"
|
||||
#import "RNSVGCGFCRule.h"
|
||||
#import "RNSVGColorMatrixType.h"
|
||||
#import "RNSVGCompositeOperator.h"
|
||||
#import "RNSVGEdgeMode.h"
|
||||
#import "RNSVGLength.h"
|
||||
#import "RNSVGMaskType.h"
|
||||
|
||||
@@ -85,6 +85,19 @@ RCT_ENUM_CONVERTER(
|
||||
SVG_FEBLEND_MODE_UNKNOWN,
|
||||
intValue)
|
||||
|
||||
RCT_ENUM_CONVERTER(
|
||||
RNSVGCompositeOperator,
|
||||
(@{
|
||||
@"over" : @(SVG_FECOMPOSITE_OPERATOR_OVER),
|
||||
@"in" : @(SVG_FECOMPOSITE_OPERATOR_IN),
|
||||
@"out" : @(SVG_FECOMPOSITE_OPERATOR_OUT),
|
||||
@"atop" : @(SVG_FECOMPOSITE_OPERATOR_ATOP),
|
||||
@"xor" : @(SVG_FECOMPOSITE_OPERATOR_XOR),
|
||||
@"arithmetic" : @(SVG_FECOMPOSITE_OPERATOR_ARITHMETIC),
|
||||
}),
|
||||
SVG_FECOMPOSITE_OPERATOR_UNKNOWN,
|
||||
intValue)
|
||||
|
||||
+ (RNSVGBrush *)RNSVGBrush:(id)json
|
||||
{
|
||||
if ([json isKindOfClass:[NSNumber class]]) {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#import <react/renderer/components/rnsvg/Props.h>
|
||||
#import "RNSVGBlendMode.h"
|
||||
#import "RNSVGColorMatrixType.h"
|
||||
#import "RNSVGCompositeOperator.h"
|
||||
#import "RNSVGEdgeMode.h"
|
||||
#import "RNSVGUnits.h"
|
||||
|
||||
@@ -13,6 +14,7 @@ namespace react = facebook::react;
|
||||
+ (RNSVGUnits)RNSVGUnitsFromPrimitiveUnitsCppEquivalent:(react::RNSVGFilterPrimitiveUnits)svgUnits;
|
||||
+ (RNSVGBlendMode)RNSVGBlendModeFromCppEquivalent:(react::RNSVGFeBlendMode)mode;
|
||||
+ (RNSVGColorMatrixType)RNSVGColorMatrixTypeFromCppEquivalent:(react::RNSVGFeColorMatrixType)type;
|
||||
+ (RNSVGCompositeOperator)RNSVGRNSVGCompositeOperatorFromCppEquivalent:(react::RNSVGFeCompositeOperator1)operator1;
|
||||
+ (RNSVGEdgeMode)RNSVGEdgeModeFromCppEquivalent:(react::RNSVGFeGaussianBlurEdgeMode)edgeMode;
|
||||
|
||||
@end
|
||||
|
||||
@@ -55,6 +55,24 @@
|
||||
}
|
||||
}
|
||||
|
||||
+ (RNSVGCompositeOperator)RNSVGRNSVGCompositeOperatorFromCppEquivalent:(react::RNSVGFeCompositeOperator1)operator1
|
||||
{
|
||||
switch (operator1) {
|
||||
case react::RNSVGFeCompositeOperator1::Over:
|
||||
return SVG_FECOMPOSITE_OPERATOR_OVER;
|
||||
case react::RNSVGFeCompositeOperator1::In:
|
||||
return SVG_FECOMPOSITE_OPERATOR_IN;
|
||||
case react::RNSVGFeCompositeOperator1::Out:
|
||||
return SVG_FECOMPOSITE_OPERATOR_OUT;
|
||||
case react::RNSVGFeCompositeOperator1::Atop:
|
||||
return SVG_FECOMPOSITE_OPERATOR_ATOP;
|
||||
case react::RNSVGFeCompositeOperator1::Xor:
|
||||
return SVG_FECOMPOSITE_OPERATOR_XOR;
|
||||
case react::RNSVGFeCompositeOperator1::Arithmetic:
|
||||
return SVG_FECOMPOSITE_OPERATOR_ARITHMETIC;
|
||||
}
|
||||
}
|
||||
|
||||
+ (RNSVGEdgeMode)RNSVGEdgeModeFromCppEquivalent:(react::RNSVGFeGaussianBlurEdgeMode)edgeMode
|
||||
{
|
||||
switch (edgeMode) {
|
||||
|
||||
5
apple/ViewManagers/RNSVGFeCompositeManager.h
Normal file
5
apple/ViewManagers/RNSVGFeCompositeManager.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#import "RNSVGFilterPrimitiveManager.h"
|
||||
|
||||
@interface RNSVGFeCompositeManager : RNSVGFilterPrimitiveManager
|
||||
|
||||
@end
|
||||
22
apple/ViewManagers/RNSVGFeCompositeManager.mm
Normal file
22
apple/ViewManagers/RNSVGFeCompositeManager.mm
Normal file
@@ -0,0 +1,22 @@
|
||||
#import "RNSVGFeCompositeManager.h"
|
||||
#import "RNSVGCompositeOperator.h"
|
||||
#import "RNSVGFeComposite.h"
|
||||
|
||||
@implementation RNSVGFeCompositeManager
|
||||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
- (RNSVGFeComposite *)node
|
||||
{
|
||||
return [RNSVGFeComposite new];
|
||||
}
|
||||
|
||||
RCT_EXPORT_VIEW_PROPERTY(in1, NSString)
|
||||
RCT_EXPORT_VIEW_PROPERTY(in2, NSString)
|
||||
RCT_EXPORT_VIEW_PROPERTY(operator1, RNSVGCompositeOperator)
|
||||
RCT_EXPORT_VIEW_PROPERTY(k1, NSNumber *)
|
||||
RCT_EXPORT_VIEW_PROPERTY(k2, NSNumber *)
|
||||
RCT_EXPORT_VIEW_PROPERTY(k3, NSNumber *)
|
||||
RCT_EXPORT_VIEW_PROPERTY(k4, NSNumber *)
|
||||
|
||||
@end
|
||||
424
apps/examples/src/examples/Filters/FeComposite.tsx
Normal file
424
apps/examples/src/examples/Filters/FeComposite.tsx
Normal file
@@ -0,0 +1,424 @@
|
||||
import {Image, Text as RNText, View} from 'react-native';
|
||||
import {
|
||||
Defs,
|
||||
FeComposite,
|
||||
FeFlood,
|
||||
FeMerge,
|
||||
FeMergeNode,
|
||||
Filter,
|
||||
G,
|
||||
Path,
|
||||
Rect,
|
||||
Svg,
|
||||
Text,
|
||||
Use,
|
||||
} from 'react-native-svg';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
QuickTestExample.title = 'Quick Test Example';
|
||||
function QuickTestExample() {
|
||||
return (
|
||||
<Svg width="200" height="150">
|
||||
<Filter id="offset" width="180" height="180">
|
||||
<FeComposite in="SourceGraphic" in2="BackgroundImage" operator="in" />
|
||||
</Filter>
|
||||
<Rect x="50" y="50" width="100" height="100" fill="red" />
|
||||
<Rect
|
||||
x="0"
|
||||
y="0"
|
||||
width="100"
|
||||
height="100"
|
||||
fill="blue"
|
||||
filter="url(#offset)"
|
||||
/>
|
||||
</Svg>
|
||||
);
|
||||
}
|
||||
|
||||
ReferenceExample.title = 'FeComposite W3 reference';
|
||||
function ReferenceExample() {
|
||||
return (
|
||||
<View style={{backgroundColor: '#fff'}}>
|
||||
<Svg width="330" height="195" viewBox="0 0 1100 650">
|
||||
<Defs>
|
||||
<Filter
|
||||
id="overFlood"
|
||||
filterUnits="objectBoundingBox"
|
||||
x="-5%"
|
||||
y="-5%"
|
||||
width="110%"
|
||||
height="110%">
|
||||
<FeFlood floodColor="#ffffff" floodOpacity="1" result="flood" />
|
||||
<FeComposite
|
||||
in="SourceGraphic"
|
||||
in2="BackgroundImage"
|
||||
operator="over"
|
||||
result="comp"
|
||||
/>
|
||||
<FeMerge>
|
||||
<FeMergeNode in="flood" />
|
||||
<FeMergeNode in="comp" />
|
||||
</FeMerge>
|
||||
</Filter>
|
||||
<Filter
|
||||
id="inFlood"
|
||||
filterUnits="objectBoundingBox"
|
||||
x="-5%"
|
||||
y="-5%"
|
||||
width="110%"
|
||||
height="110%">
|
||||
<FeFlood floodColor="#ffffff" floodOpacity="1" result="flood" />
|
||||
<FeComposite
|
||||
in="SourceGraphic"
|
||||
in2="BackgroundImage"
|
||||
operator="in"
|
||||
result="comp"
|
||||
/>
|
||||
<FeMerge>
|
||||
<FeMergeNode in="flood" />
|
||||
<FeMergeNode in="comp" />
|
||||
</FeMerge>
|
||||
</Filter>
|
||||
<Filter
|
||||
id="outFlood"
|
||||
filterUnits="objectBoundingBox"
|
||||
x="-5%"
|
||||
y="-5%"
|
||||
width="110%"
|
||||
height="110%">
|
||||
<FeFlood floodColor="#ffffff" floodOpacity="1" result="flood" />
|
||||
<FeComposite
|
||||
in="SourceGraphic"
|
||||
in2="BackgroundImage"
|
||||
operator="out"
|
||||
result="comp"
|
||||
/>
|
||||
<FeMerge>
|
||||
<FeMergeNode in="flood" />
|
||||
<FeMergeNode in="comp" />
|
||||
</FeMerge>
|
||||
</Filter>
|
||||
<Filter
|
||||
id="atopFlood"
|
||||
filterUnits="objectBoundingBox"
|
||||
x="-5%"
|
||||
y="-5%"
|
||||
width="110%"
|
||||
height="110%">
|
||||
<FeFlood floodColor="#ffffff" floodOpacity="1" result="flood" />
|
||||
<FeComposite
|
||||
in="SourceGraphic"
|
||||
in2="BackgroundImage"
|
||||
operator="atop"
|
||||
result="comp"
|
||||
/>
|
||||
<FeMerge>
|
||||
<FeMergeNode in="flood" />
|
||||
<FeMergeNode in="comp" />
|
||||
</FeMerge>
|
||||
</Filter>
|
||||
<Filter
|
||||
id="xorFlood"
|
||||
filterUnits="objectBoundingBox"
|
||||
x="-5%"
|
||||
y="-5%"
|
||||
width="110%"
|
||||
height="110%">
|
||||
<FeFlood floodColor="#ffffff" floodOpacity="1" result="flood" />
|
||||
<FeComposite
|
||||
in="SourceGraphic"
|
||||
in2="BackgroundImage"
|
||||
operator="xor"
|
||||
result="comp"
|
||||
/>
|
||||
<FeMerge>
|
||||
<FeMergeNode in="flood" />
|
||||
<FeMergeNode in="comp" />
|
||||
</FeMerge>
|
||||
</Filter>
|
||||
<Filter
|
||||
id="arithmeticFlood"
|
||||
filterUnits="objectBoundingBox"
|
||||
x="-5%"
|
||||
y="-5%"
|
||||
width="110%"
|
||||
height="110%">
|
||||
<FeFlood floodColor="#ffffff" floodOpacity="1" result="flood" />
|
||||
<FeComposite
|
||||
in="SourceGraphic"
|
||||
in2="BackgroundImage"
|
||||
result="comp"
|
||||
operator="arithmetic"
|
||||
k1=".5"
|
||||
k2=".5"
|
||||
k3=".5"
|
||||
k4=".5"
|
||||
/>
|
||||
<FeMerge>
|
||||
<FeMergeNode in="flood" />
|
||||
<FeMergeNode in="comp" />
|
||||
</FeMerge>
|
||||
</Filter>
|
||||
<Filter
|
||||
id="overNoFlood"
|
||||
filterUnits="objectBoundingBox"
|
||||
x="-5%"
|
||||
y="-5%"
|
||||
width="110%"
|
||||
height="110%">
|
||||
<FeComposite
|
||||
in="SourceGraphic"
|
||||
in2="BackgroundImage"
|
||||
operator="over"
|
||||
result="comp"
|
||||
/>
|
||||
</Filter>
|
||||
<Filter
|
||||
id="inNoFlood"
|
||||
filterUnits="objectBoundingBox"
|
||||
x="-5%"
|
||||
y="-5%"
|
||||
width="110%"
|
||||
height="110%">
|
||||
<FeComposite
|
||||
in="SourceGraphic"
|
||||
in2="BackgroundImage"
|
||||
operator="in"
|
||||
result="comp"
|
||||
/>
|
||||
</Filter>
|
||||
<Filter
|
||||
id="outNoFlood"
|
||||
filterUnits="objectBoundingBox"
|
||||
x="-5%"
|
||||
y="-5%"
|
||||
width="110%"
|
||||
height="110%">
|
||||
<FeComposite
|
||||
in="SourceGraphic"
|
||||
in2="BackgroundImage"
|
||||
operator="out"
|
||||
result="comp"
|
||||
/>
|
||||
</Filter>
|
||||
<Filter
|
||||
id="atopNoFlood"
|
||||
filterUnits="objectBoundingBox"
|
||||
x="-5%"
|
||||
y="-5%"
|
||||
width="110%"
|
||||
height="110%">
|
||||
<FeComposite
|
||||
in="SourceGraphic"
|
||||
in2="BackgroundImage"
|
||||
operator="atop"
|
||||
result="comp"
|
||||
/>
|
||||
</Filter>
|
||||
<Filter
|
||||
id="xorNoFlood"
|
||||
filterUnits="objectBoundingBox"
|
||||
x="-5%"
|
||||
y="-5%"
|
||||
width="110%"
|
||||
height="110%">
|
||||
<FeComposite
|
||||
in="SourceGraphic"
|
||||
in2="BackgroundImage"
|
||||
operator="xor"
|
||||
result="comp"
|
||||
/>
|
||||
</Filter>
|
||||
<Filter
|
||||
id="arithmeticNoFlood"
|
||||
filterUnits="objectBoundingBox"
|
||||
x="-5%"
|
||||
y="-5%"
|
||||
width="110%"
|
||||
height="110%">
|
||||
<FeComposite
|
||||
in="SourceGraphic"
|
||||
in2="BackgroundImage"
|
||||
result="comp"
|
||||
operator="arithmetic"
|
||||
k1=".5"
|
||||
k2=".5"
|
||||
k3=".5"
|
||||
k4=".5"
|
||||
/>
|
||||
</Filter>
|
||||
<Path id="Blue100" d="M 0 0 L 100 0 L 100 100 z" fill="#00ffff" />
|
||||
<Path id="Red100" d="M 0 0 L 0 100 L 100 0 z" fill="#ff00ff" />
|
||||
<Path
|
||||
id="Blue50"
|
||||
d="M 0 125 L 100 125 L 100 225 z"
|
||||
fill="#00ffff"
|
||||
fillOpacity=".5"
|
||||
/>
|
||||
<Path
|
||||
id="Red50"
|
||||
d="M 0 125 L 0 225 L 100 125 z"
|
||||
fill="#ff00ff"
|
||||
fillOpacity=".5"
|
||||
/>
|
||||
<G id="TwoBlueTriangles">
|
||||
<Use href="#Blue100" />
|
||||
<Use href="#Blue50" />
|
||||
</G>
|
||||
<G id="BlueTriangles">
|
||||
<Use transform="translate(275,25)" href="#TwoBlueTriangles" />
|
||||
<Use transform="translate(400,25)" href="#TwoBlueTriangles" />
|
||||
<Use transform="translate(525,25)" href="#TwoBlueTriangles" />
|
||||
<Use transform="translate(650,25)" href="#TwoBlueTriangles" />
|
||||
<Use transform="translate(775,25)" href="#TwoBlueTriangles" />
|
||||
<Use transform="translate(900,25)" href="#TwoBlueTriangles" />
|
||||
</G>
|
||||
</Defs>
|
||||
|
||||
<Rect fill="none" stroke="blue" x="1" y="1" width="1098" height="648" />
|
||||
<G font-family="Verdana" fontSize="40" shape-rendering="crispEdges">
|
||||
<G enable-background="new">
|
||||
<Text x="15" y="75">
|
||||
opacity 1.0
|
||||
</Text>
|
||||
<Text x="15" y="115" fontSize="27">
|
||||
(with FeFlood)
|
||||
</Text>
|
||||
<Text x="15" y="200">
|
||||
opacity 0.5
|
||||
</Text>
|
||||
<Text x="15" y="240" fontSize="27">
|
||||
(with FeFlood)
|
||||
</Text>
|
||||
<Use href="#BlueTriangles" />
|
||||
<G transform="translate(275,25)">
|
||||
<Use href="#Red100" filter="url(#overFlood)" />
|
||||
<Use href="#Red50" filter="url(#overFlood)" />
|
||||
<Text x="5" y="275">
|
||||
over
|
||||
</Text>
|
||||
</G>
|
||||
<G transform="translate(400,25)">
|
||||
<Use href="#Red100" filter="url(#inFlood)" />
|
||||
<Use href="#Red50" filter="url(#inFlood)" />
|
||||
<Text x="35" y="275">
|
||||
in
|
||||
</Text>
|
||||
</G>
|
||||
<G transform="translate(525,25)">
|
||||
<Use href="#Red100" filter="url(#outFlood)" />
|
||||
<Use href="#Red50" filter="url(#outFlood)" />
|
||||
<Text x="15" y="275">
|
||||
out
|
||||
</Text>
|
||||
</G>
|
||||
<G transform="translate(650,25)">
|
||||
<Use href="#Red100" filter="url(#atopFlood)" />
|
||||
<Use href="#Red50" filter="url(#atopFlood)" />
|
||||
<Text x="10" y="275">
|
||||
atop
|
||||
</Text>
|
||||
</G>
|
||||
<G transform="translate(775,25)">
|
||||
<Use href="#Red100" filter="url(#xorFlood)" />
|
||||
<Use href="#Red50" filter="url(#xorFlood)" />
|
||||
<Text x="15" y="275">
|
||||
xor
|
||||
</Text>
|
||||
</G>
|
||||
<G transform="translate(900,25)">
|
||||
<Use href="#Red100" filter="url(#arithmeticFlood)" />
|
||||
<Use href="#Red50" filter="url(#arithmeticFlood)" />
|
||||
<Text x="-25" y="275">
|
||||
arithmetic
|
||||
</Text>
|
||||
</G>
|
||||
</G>
|
||||
<G transform="translate(0,325)" enable-background="new">
|
||||
<Text x="15" y="75">
|
||||
opacity 1.0
|
||||
</Text>
|
||||
<Text x="15" y="115" fontSize="27">
|
||||
(without FeFlood)
|
||||
</Text>
|
||||
<Text x="15" y="200">
|
||||
opacity 0.5
|
||||
</Text>
|
||||
<Text x="15" y="240" fontSize="27">
|
||||
(without FeFlood)
|
||||
</Text>
|
||||
<Use href="#BlueTriangles" />
|
||||
<G transform="translate(275,25)">
|
||||
<Use href="#Red100" filter="url(#overNoFlood)" />
|
||||
<Use href="#Red50" filter="url(#overNoFlood)" />
|
||||
<Text x="5" y="275">
|
||||
over
|
||||
</Text>
|
||||
</G>
|
||||
<G transform="translate(400,25)">
|
||||
<Use href="#Red100" filter="url(#inNoFlood)" />
|
||||
<Use href="#Red50" filter="url(#inNoFlood)" />
|
||||
<Text x="35" y="275">
|
||||
in
|
||||
</Text>
|
||||
</G>
|
||||
<G transform="translate(525,25)">
|
||||
<Use href="#Red100" filter="url(#outNoFlood)" />
|
||||
<Use href="#Red50" filter="url(#outNoFlood)" />
|
||||
<Text x="15" y="275">
|
||||
out
|
||||
</Text>
|
||||
</G>
|
||||
<G transform="translate(650,25)">
|
||||
<Use href="#Red100" filter="url(#atopNoFlood)" />
|
||||
<Use href="#Red50" filter="url(#atopNoFlood)" />
|
||||
<Text x="10" y="275">
|
||||
atop
|
||||
</Text>
|
||||
</G>
|
||||
<G transform="translate(775,25)">
|
||||
<Use href="#Red100" filter="url(#xorNoFlood)" />
|
||||
<Use href="#Red50" filter="url(#xorNoFlood)" />
|
||||
<Text x="15" y="275">
|
||||
xor
|
||||
</Text>
|
||||
</G>
|
||||
<G transform="translate(900,25)">
|
||||
<Use href="#Red100" filter="url(#arithmeticNoFlood)" />
|
||||
<Use href="#Red50" filter="url(#arithmeticNoFlood)" />
|
||||
<Text x="-25" y="275">
|
||||
arithmetic
|
||||
</Text>
|
||||
</G>
|
||||
</G>
|
||||
</G>
|
||||
</Svg>
|
||||
<RNText>W3 Reference</RNText>
|
||||
<Image source={require('./feComposite.png')} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const icon = (
|
||||
<Svg height="30" width="30" viewBox="0 0 20 20">
|
||||
<Filter id="iconCompositeIn" width="200%">
|
||||
<FeComposite
|
||||
in="SourceGraphic"
|
||||
in2="BackgroundImage"
|
||||
operator="in"
|
||||
result="comp"
|
||||
/>
|
||||
</Filter>
|
||||
<Path id="Blue100" d="M 0 0 L 20 0 L 20 20 z" fill="#00ffff" />
|
||||
<Path
|
||||
id="Red100"
|
||||
d="M 0 0 L 0 20 L 20 0 z"
|
||||
fill="#ff00ff"
|
||||
filter="url(#iconCompositeIn)"
|
||||
/>
|
||||
</Svg>
|
||||
);
|
||||
const samples = [QuickTestExample, ReferenceExample];
|
||||
|
||||
export {icon, samples};
|
||||
BIN
apps/examples/src/examples/Filters/feComposite.png
Normal file
BIN
apps/examples/src/examples/Filters/feComposite.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.7 KiB |
@@ -2,6 +2,7 @@ import React from 'react';
|
||||
import Svg, {Circle} from 'react-native-svg';
|
||||
import * as FeBlend from './FeBlend';
|
||||
import * as FeColorMatrix from './FeColorMatrix';
|
||||
import * as FeComposite from './FeComposite';
|
||||
import * as FeFlood from './FeFlood';
|
||||
import * as FeGaussianBlur from './FeGaussianBlur';
|
||||
import * as FeMerge from './FeMerge';
|
||||
@@ -11,6 +12,7 @@ import * as ReanimatedFeColorMatrix from './ReanimatedFeColorMatrix';
|
||||
const samples = {
|
||||
FeBlend,
|
||||
FeColorMatrix,
|
||||
FeComposite,
|
||||
FeFlood,
|
||||
FeGaussianBlur,
|
||||
FeMerge,
|
||||
|
||||
@@ -61,7 +61,8 @@
|
||||
"e2e": "jest e2e",
|
||||
"generateE2eReferences": "ts-node e2e/generateReferences.ts",
|
||||
"check-archs-consistency": "node ./scripts/codegen-check-consistency.js",
|
||||
"sync-archs": "node ./scripts/codegen-sync-archs.js"
|
||||
"sync-archs": "node ./scripts/codegen-sync-archs.js",
|
||||
"metal-to-ci": "node ./scripts/metal.js"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "*",
|
||||
|
||||
@@ -19,6 +19,7 @@ module.exports = {
|
||||
'RNSVGDefsComponentDescriptor',
|
||||
'RNSVGFeBlendComponentDescriptor',
|
||||
'RNSVGFeColorMatrixComponentDescriptor',
|
||||
'RNSVGFeCompositeComponentDescriptor',
|
||||
'RNSVGFeFloodComponentDescriptor',
|
||||
'RNSVGFeGaussianBlurComponentDescriptor',
|
||||
'RNSVGFeMergeComponentDescriptor',
|
||||
|
||||
56
scripts/metal.js
Normal file
56
scripts/metal.js
Normal file
@@ -0,0 +1,56 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { execSync } = require('child_process');
|
||||
|
||||
const ROOT_DIR = path.resolve(__dirname, '..');
|
||||
const FILTERS_DIR = path.resolve(ROOT_DIR, 'apple/Filters/MetalCI');
|
||||
|
||||
function exec(command) {
|
||||
execSync(command);
|
||||
}
|
||||
|
||||
function clearGeneratedFiles() {
|
||||
const files = fs.readdirSync(FILTERS_DIR);
|
||||
console.log('Removing generated files...');
|
||||
files.forEach((file) => {
|
||||
const filePath = path.join(FILTERS_DIR, file);
|
||||
const fileExtension = path.extname(file);
|
||||
if (fileExtension === '.air' || fileExtension === '.metallib') {
|
||||
exec(`rm -rf ${filePath}`);
|
||||
}
|
||||
});
|
||||
console.log('Generated files removed.');
|
||||
}
|
||||
|
||||
function compileMetalFile(file, sdk) {
|
||||
const filePath = path.join(FILTERS_DIR, file);
|
||||
const fileName = path.basename(filePath).replace('.metal', '');
|
||||
const filePathWithoutExt = path.join(FILTERS_DIR, file).replace('.metal', '');
|
||||
console.log('* for ' + sdk);
|
||||
exec(
|
||||
`xcrun -sdk ${sdk} metal -fcikernel -c ${filePathWithoutExt}.metal -o ${filePathWithoutExt}.${sdk}.air`
|
||||
);
|
||||
console.log(` ├─ ${fileName}.${sdk}.air`);
|
||||
exec(
|
||||
`xcrun -sdk ${sdk} metallib -cikernel ${filePathWithoutExt}.${sdk}.air -o ${filePathWithoutExt}.${sdk}.metallib`
|
||||
);
|
||||
console.log(` └─ ${fileName}.${sdk}.metallib`);
|
||||
}
|
||||
|
||||
function generateMetallib() {
|
||||
const files = fs.readdirSync(FILTERS_DIR);
|
||||
files.forEach((file) => {
|
||||
const fileExtension = path.extname(file);
|
||||
if (fileExtension === '.metal') {
|
||||
const fileName = path.basename(file).replace('.metal', '');
|
||||
console.log('Compiling:', fileName + '.metal');
|
||||
compileMetalFile(file, 'macosx');
|
||||
compileMetalFile(file, 'iphoneos');
|
||||
compileMetalFile(file, 'appletvos');
|
||||
compileMetalFile(file, 'xros');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
clearGeneratedFiles();
|
||||
generateMetallib();
|
||||
@@ -26,6 +26,7 @@ import {
|
||||
RNSVGDefs,
|
||||
RNSVGEllipse,
|
||||
RNSVGFeColorMatrix,
|
||||
RNSVGFeComposite,
|
||||
RNSVGFeGaussianBlur,
|
||||
RNSVGFeMerge,
|
||||
RNSVGFeOffset,
|
||||
@@ -125,6 +126,7 @@ export {
|
||||
RNSVGDefs,
|
||||
RNSVGEllipse,
|
||||
RNSVGFeColorMatrix,
|
||||
RNSVGFeComposite,
|
||||
RNSVGFeGaussianBlur,
|
||||
RNSVGFeMerge,
|
||||
RNSVGFeOffset,
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
import { NativeMethods } from 'react-native';
|
||||
import RNSVGFeComposite from '../../fabric/FeCompositeNativeComponent';
|
||||
import {
|
||||
extractFeComposite,
|
||||
extractFilter,
|
||||
} from '../../lib/extract/extractFilter';
|
||||
import { NumberProp } from '../../lib/extract/types';
|
||||
import { warnUnimplementedFilter } from '../../lib/util';
|
||||
import FilterPrimitive from './FilterPrimitive';
|
||||
|
||||
type FeCompositeOperator =
|
||||
@@ -28,7 +33,14 @@ export default class FeComposite extends FilterPrimitive<FeCompositeProps> {
|
||||
};
|
||||
|
||||
render() {
|
||||
warnUnimplementedFilter();
|
||||
return null;
|
||||
return (
|
||||
<RNSVGFeComposite
|
||||
ref={(ref) =>
|
||||
this.refMethod(ref as (FeComposite & NativeMethods) | null)
|
||||
}
|
||||
{...extractFilter(this.props)}
|
||||
{...extractFeComposite(this.props)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
34
src/fabric/FeCompositeNativeComponent.ts
Normal file
34
src/fabric/FeCompositeNativeComponent.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
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 FeCompositeOperator =
|
||||
| 'over'
|
||||
| 'in'
|
||||
| 'out'
|
||||
| 'atop'
|
||||
| 'xor'
|
||||
| 'arithmetic';
|
||||
|
||||
interface FilterPrimitiveCommonProps {
|
||||
x?: UnsafeMixed<NumberProp>;
|
||||
y?: UnsafeMixed<NumberProp>;
|
||||
width?: UnsafeMixed<NumberProp>;
|
||||
height?: UnsafeMixed<NumberProp>;
|
||||
result?: string;
|
||||
}
|
||||
|
||||
export interface NativeProps extends ViewProps, FilterPrimitiveCommonProps {
|
||||
in1?: string;
|
||||
in2?: string;
|
||||
operator1?: WithDefault<FeCompositeOperator, 'over'>;
|
||||
k1?: Float;
|
||||
k2?: Float;
|
||||
k3?: Float;
|
||||
k4?: Float;
|
||||
}
|
||||
|
||||
export default codegenNativeComponent<NativeProps>('RNSVGFeComposite');
|
||||
@@ -23,6 +23,7 @@ import RNSVGUse from './UseNativeComponent';
|
||||
import RNSVGFilter from './FilterNativeComponent';
|
||||
import RNSVGFeBlend from './FeBlendNativeComponent';
|
||||
import RNSVGFeColorMatrix from './FeColorMatrixNativeComponent';
|
||||
import RNSVGFeComposite from './FeCompositeNativeComponent';
|
||||
import RNSVGFeFlood from './FeFloodNativeComponent';
|
||||
import RNSVGFeGaussianBlur from './FeGaussianBlurNativeComponent';
|
||||
import RNSVGFeMerge from './FeMergeNativeComponent';
|
||||
@@ -54,6 +55,7 @@ export {
|
||||
RNSVGFilter,
|
||||
RNSVGFeBlend,
|
||||
RNSVGFeColorMatrix,
|
||||
RNSVGFeComposite,
|
||||
RNSVGFeFlood,
|
||||
RNSVGFeGaussianBlur,
|
||||
RNSVGFeMerge,
|
||||
|
||||
@@ -2,11 +2,13 @@ import React from 'react';
|
||||
import { ColorValue, processColor } from 'react-native';
|
||||
import { FeBlendProps as FeBlendComponentProps } from '../../elements/filters/FeBlend';
|
||||
import { FeColorMatrixProps as FeColorMatrixComponentProps } from '../../elements/filters/FeColorMatrix';
|
||||
import { FeCompositeProps as FeCompositeComponentProps } from '../../elements/filters/FeComposite';
|
||||
import { FeFloodProps as FeFloodComponentProps } from '../../elements/filters/FeFlood';
|
||||
import { FeGaussianBlurProps as FeGaussianBlurComponentProps } from '../../elements/filters/FeGaussianBlur';
|
||||
import { FeMergeProps as FeMergeComponentProps } from '../../elements/filters/FeMerge';
|
||||
import { NativeProps as FeBlendNativeProps } from '../../fabric/FeBlendNativeComponent';
|
||||
import { NativeProps as FeColorMatrixNativeProps } from '../../fabric/FeColorMatrixNativeComponent';
|
||||
import { NativeProps as FeCompositeNativeProps } from '../../fabric/FeCompositeNativeComponent';
|
||||
import { NativeProps as FeFloodNativeProps } from '../../fabric/FeFloodNativeComponent';
|
||||
import { NativeProps as FeGaussianBlurNativeProps } from '../../fabric/FeGaussianBlurNativeComponent';
|
||||
import { NativeProps as FeMergeNativeProps } from '../../fabric/FeMergeNativeComponent';
|
||||
@@ -89,6 +91,24 @@ export const extractFeColorMatrix = (
|
||||
return extracted;
|
||||
};
|
||||
|
||||
export const extractFeComposite = (
|
||||
props: FeCompositeComponentProps
|
||||
): FeCompositeNativeProps => {
|
||||
const extracted: FeCompositeNativeProps = {
|
||||
in1: props.in || '',
|
||||
in2: props.in2 || '',
|
||||
operator1: props.operator || 'over',
|
||||
};
|
||||
|
||||
(['k1', 'k2', 'k3', 'k4'] as const).forEach((key) => {
|
||||
if (props[key] !== undefined) {
|
||||
extracted[key] = Number(props[key]) || 0;
|
||||
}
|
||||
});
|
||||
|
||||
return extracted;
|
||||
};
|
||||
|
||||
const defaultFill = { type: 0, payload: processColor('black') as ColorValue };
|
||||
export default function extractFeFlood(
|
||||
props: FeFloodComponentProps
|
||||
|
||||
Reference in New Issue
Block a user