-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Shadows, filters plans #150
Comments
Any updates about this? |
@webschik did you manage to find a solution regarding this either beit a native one? |
@jakelacey2012, unfortunately not |
Thank you very much for this great library! Are there any updates on this? |
I think the main difficulty is because of SVG API, for example (this is taken from w3schools lol):
And it will produce: Not only the code for |
If someone is interested in working on this, they can probably get some inspiration from how the mask element was implemented recently: In order to compute the mask for blending the images, it implements and uses the luminanceToAlpha type of feColorMatrix filter: <filter id="luminanceToAlpha" filterUnits="objectBoundingBox">
<feColorMatrix id="luminance-value" type="luminanceToAlpha" in="SourceGraphic"/>
</filter> ios: |
Essentially it entails adding some logic where it now renders to the current context; to instead check if the current element has the filter attribute set, if so: create a map initialised to have the SourceGraphic bitmap, then compute the output of each filter primitive in the referenced filter element in order and store the outputs in the map with the ids as the keys. Then rendering the final output instead. Blending is also demonstrated by the mask logic. |
@msand, hello Mikael. I was recently looking to port some functionality from my ionic app to a react-native app. My obstacle is that I have glow effects on SVG elements and I would need react-native-svg support for the following tags: filter, feGaussianBlur, feMerge, and feMergeNode. Is this something we could work together, on. I'd love to see this support added as I think many people would benefit from it, myself included. I'm pretty new to react, so what's your impression of the level of difficulty to add svg filter support? |
@glthomas Great to hear :) The react part of it is relatively small, most of the work will probably be around implementing the bitmap filters on android and ios. Could possibly use GPUImage or GPUImage2 or plain core image on ios, and one of the gpuimage ports or renderscript on android. Alternatively, plain cpu based implementations in java and obj-c might be good enough for most static use cases, and at least simpler to get the build environment set up. Or how experienced are you in c++? |
Actually, if you only need blur, then at least on android it's possible to implement it using https://developer.android.com/reference/android/renderscript/ScriptIntrinsicBlur |
It seems renderscript will almost certainly be the fastest implementation available on android: https://android-developers.googleblog.com/2013/08/renderscript-intrinsics.html RenderScript rs = RenderScript.create(theActivity);
ScriptIntrinsicBlur theIntrinsic = ScriptIntrinsicBlur.create(mRS, Element.U8_4(rs));;
Allocation tmpIn = Allocation.createFromBitmap(rs, inputBitmap);
Allocation tmpOut = Allocation.createFromBitmap(rs, outputBitmap);
theIntrinsic.setRadius(25.f);
theIntrinsic.setInput(tmpIn);
theIntrinsic.forEach(tmpOut);
tmpOut.copyTo(outputBitmap); Can probably get some inspiration for optimisations from here: https://github.com/react-native-community/react-native-blur/blob/master/android/src/main/java/com/cmcewen/blurview/BlurringView.java |
And for iOS something like this: https://stackoverflow.com/a/28614430/1925631 // Needs CoreImage.framework
- (UIImage *)blurredImageWithImage:(UIImage *)sourceImage{
// Create our blurred image
CIContext *context = [CIContext contextWithOptions:nil];
CIImage *inputImage = [CIImage imageWithCGImage:sourceImage.CGImage];
// Setting up Gaussian Blur
CIFilter *filter = [CIFilter filterWithName:@"CIGaussianBlur"];
[filter setValue:inputImage forKey:kCIInputImageKey];
[filter setValue:[NSNumber numberWithFloat:15.0f] forKey:@"inputRadius"];
CIImage *result = [filter valueForKey:kCIOutputImageKey];
/* CIGaussianBlur has a tendency to shrink the image a little, this ensures it matches
* up exactly to the bounds of our original image */
CGImageRef cgImage = [context createCGImage:result fromRect:[inputImage extent]];
UIImage *retVal = [UIImage imageWithCGImage:cgImage];
if (cgImage) {
CGImageRelease(cgImage);
}
return retVal;
} |
So, now the boilerplate for the elements and filter attribute would be needed, and of course, the main work of making the filter element create a rendering pipeline according to the svg compositing model: render > filter > clip > mask > blend > composite, so filters need to happen before the current clipping logic. https://www.w3.org/TR/SVG2/render.html#FilteringPaintRegions If the value of the filter property is none then there is no filter effect applied. Otherwise, the list of functions are applied in the order provided.
The first filter function or filter reference in the list takes the element (SourceGraphic) as the input image. Subsequent operations take the output from the previous filter function or filter reference as the input image. filter element reference functions can specify an alternate input, but still uses the previous output as its SourceGraphic. Filter functions must operate in the sRGB color space. A computed value of other than none results in the creation of a stacking context [CSS21] the same way that CSS opacity does. All the elements descendants are rendered together as a group with the filter effect applied to the group as a whole. The filter property has no effect on the geometry of the target element’s CSS boxes, even though filter can cause painting outside of an element’s border box. Conceptually, any parts of the drawing are effected by filter operations. This includes any content, background, borders, text decoration, outline and visible scrolling mechanism of the element to which the filter is applied, and those of its descendants. The filter operations are applied in the element’s user coordinate system. The compositing model follows the SVG compositing model [SVG11]: first any filter effect is applied, then any clipping, masking and opacity. As per SVG, the application of filter has no effect on hit-testing. |
@msand, I’m doing my best to follow along. I’ve got a lot of catch up to do, but I am going through the things you are writing here. I also started looking at the “how to” build a react native bridge. |
@glthomas Does this help? How much experience do you have with java and objective-c? What parts would you be interested in working on? Perhaps I can give some more specific advice how to get some first steps going. |
Oh, my cache updated once I sent the message, didn't see your reply before sending. |
Latest draft of the Filter Effects Module https://drafts.fxtf.org/filter-effects/ |
Needed interfaces for the elements and the bridge: https://drafts.fxtf.org/filter-effects/#idl-index interface mixin SVGURIReference {
[SameObject] readonly attribute SVGAnimatedString href;
};
interface SVGFilterElement : SVGElement {
readonly attribute SVGAnimatedEnumeration filterUnits;
readonly attribute SVGAnimatedEnumeration primitiveUnits;
readonly attribute SVGAnimatedLength x;
readonly attribute SVGAnimatedLength y;
readonly attribute SVGAnimatedLength width;
readonly attribute SVGAnimatedLength height;
};
SVGFilterElement includes SVGURIReference;
interface mixin SVGFilterPrimitiveStandardAttributes {
readonly attribute SVGAnimatedLength x;
readonly attribute SVGAnimatedLength y;
readonly attribute SVGAnimatedLength width;
readonly attribute SVGAnimatedLength height;
readonly attribute SVGAnimatedString result;
};
interface SVGFEGaussianBlurElement : SVGElement {
// Edge Mode Values
const unsigned short SVG_EDGEMODE_UNKNOWN = 0;
const unsigned short SVG_EDGEMODE_DUPLICATE = 1;
const unsigned short SVG_EDGEMODE_WRAP = 2;
const unsigned short SVG_EDGEMODE_NONE = 3;
readonly attribute SVGAnimatedString in1;
readonly attribute SVGAnimatedNumber stdDeviationX;
readonly attribute SVGAnimatedNumber stdDeviationY;
readonly attribute SVGAnimatedEnumeration edgeMode;
void setStdDeviation(float stdDeviationX, float stdDeviationY);
};
SVGFEGaussianBlurElement includes SVGFilterPrimitiveStandardAttributes;
interface SVGFEMergeElement : SVGElement {
};
SVGFEMergeElement includes SVGFilterPrimitiveStandardAttributes;
interface SVGFEMergeNodeElement : SVGElement {
readonly attribute SVGAnimatedString in1;
};
|
Started work on the boilerplate: 448e795 |
@msand, how can I pull this 448e795 commit. Is it on a special branch that I can't see? Also, I managed to get a react-native starter project working and was able to link it to this library. I was able to get the demo code up and running on my device. Just trying to lay the ground work so that I can start poking at this library some more and gradually begin contributing on the filter work. One thing I'll need to learn is how to make my react-native application link to an in-develop state of the react-native-svg library. That way as I'm making changes I can test them right away. |
Its in my fork here: https://github.com/msand/react-native-svg/tree/filters?files=1 |
@msand I've cloned your filters branch and committed the interface for the RNSVGFilter.h for ios. However, I am unable to push up to your forked repo. What's the preferred process for contributing. Is it better if I fork your fork and then I submit a pull request at some point down the line when I have a few more files to contribute? |
@glthomas Great! It might make sense to rebase onto master of the main repo as well. Actually, fork this repo and make a PR here instead. I only use that one for private testing and preparing my own PRs. |
@msand I created a Pull Request to your filters branch on your forked repo. Not sure what you meant by rebasing. I anticipate multiple pull requests onto your filters branch. I'm hoping we can use the multiple PR's to serve the purpose of code reviews as this will be very much a learning process especially as it pertains to the Objective-C, which is entirely new to me. I think once we are satisfied that we have solid functionality on your filters branch and it's well tested, we can then PR this up to master. Does this sound like a good plan? |
@glthomas Sounds good. I rebased onto master here and pushed to the filters-branch, lets use this one going forwards. Please feel free to ask anything if there's something I might be able to help explain. I've learned obj-c by maintaining this project, didn't have any previous experience with anything apple/mac/ios/obj-c related before that (summer last year). So I have a relatively fresh learning experience of that as well and can probably save you some time. |
@msand, so I’ve been studying the existing elements as well as your previous comments and trying to determine the next steps beyond adding the interfaces. My focus initially will be on iOS. Referring back to your comment from 19 days ago you mentioned “main work of making the filter element create a rendering pipeline according to the svg compositing model”. As best as I can tell this means modifying the RNSVGRenerable.m file to include the code needed to handle the filtering (Possibly within the renderTo method and very near the if(self.mask) conditional. Beyond that I’m a bit lost how to proceed with regards to utilizing the the feMergeNode(s). Not too worried about learning objective-c. It’s starting to make sense after staring at it for a while. |
@glthomas Excellent, seem you're on the right track. First extract a method to render a node to a I think we should extract the static CIImage *applyLuminanceToAlphaFilter(CIImage *inputImage)
{
CIFilter *luminanceToAlpha = [CIFilter filterWithName:@"CIColorMatrix"];
[luminanceToAlpha setDefaults];
CGFloat alpha[4] = {0.2125, 0.7154, 0.0721, 0};
CGFloat zero[4] = {0, 0, 0, 0};
[luminanceToAlpha setValue:inputImage forKey:@"inputImage"];
[luminanceToAlpha setValue:[CIVector vectorWithValues:zero count:4] forKey:@"inputRVector"];
[luminanceToAlpha setValue:[CIVector vectorWithValues:zero count:4] forKey:@"inputGVector"];
[luminanceToAlpha setValue:[CIVector vectorWithValues:zero count:4] forKey:@"inputBVector"];
[luminanceToAlpha setValue:[CIVector vectorWithValues:alpha count:4] forKey:@"inputAVector"];
[luminanceToAlpha setValue:[CIVector vectorWithValues:zero count:4] forKey:@"inputBiasVector"];
return [luminanceToAlpha valueForKey:@"outputImage"];
}
So, another method to apply a filter primitive to a Then we should add a method on the RNSVGSvgView, similar to [self.svgView getDefinedMask:self.mask] but getDefinedFilter:self.filter instead And then a method on RNSVGFilter, to process a Once we have at least a single filter primitive, and the rendering into a |
For the feMergeNodes, we should have the parseReference method of the RNSVGFilter to set up a filter graph (map from index/name to filter instance, and the outputs of instances are set as inputs to any others which reference them), such that after setting the source graphic on the first filter primitive and we call createCGImage on the CIImage of the output node, the CIFIlter pipeline handles computing all the needed filters, where the merge nodes do something like this: CIFilter *filter = [CIFilter filterWithName:@"CISourceOverCompositing"];
[filter setValue:background forKey:kCIInputBackgroundImageKey];
[filter setValue:foreground forKey:kCIInputImageKey];
CIImage *outputImage = [filter outputImage]; Or, simply: [foreground imageByCompositingOverImage:background] If I've understood/remember correctly then if we keep it as CIFIlter and CIImage until the actual rendering (createCGImage), it shouldn't process redundant filters in the graph. (i.e., ones which aren't connected to the output node) And it should create less intermediate processing/memory management pressure. |
svg should be done in open gl. |
Any updates or plans here? |
Hey @msand is there an estimated eta on this feature? I see that it is being worked on and need to make a product direction decision based on this so would be really helpful to have some sort of estimate. 👍👍 Thanks |
I'm a maintainer of react-native-skia and it might be a better alternative for such effects. We support most of them (blur, noise, displacement maps etc). |
Is there a tool that exists or could use contributors for taking svg and converting to skia components? |
you can display svg images: https://shopify.github.io/react-native-skia/docs/images-svg and even animate with a bit of imagination: https://twitter.com/wcandillon/status/1515731236861493258 Deeper SVG integrations will come in the future but right now this is not the most pressing issue on our side. Maybe it will be done by the community. Meanwhile, SVG concepts can easily be mapped to our declarative Skia API, we will try to document the process a little bit more. But you can find a video that does a lot figma to skia conversions at https://www.youtube.com/watch?v=GFssmWUhwww |
hi @wcandillon , Is this demo available in the react-native-skia project? |
This is the SVG documentation: https://shopify.github.io/react-native-skia/docs/images-svg/ |
Waiting for working with svg shadows directly in |
^^^^^^^ |
I just stumbled upon this issue. I'm sad this is currently not available, but I'm even more disappointed by the level of entitlement in this thread. The work here is clearly not making progress, and keeping asking for timelines on it is not how open source works. If you have a business decision depending on a feature that is not available, you should probably dedicate time from your team to implement it, baking that in your estimates, and contributing to grow the project. That's how open source works. If you or your team can't take the work, then the decision has likely been made: You can't use it. As an alternative look at the feasibility of what William has posted above, but please, don't keep calling it important and asking for status if there's clearly no progress happening, as it won't magically get the feature landed. Go figure out an alternative or get your hands dirty to solve the problem. Sorry if this is rude and is just adding more noise here, but come on people... This is open source! |
The upgrade costs are too high |
+1 |
I think that in SVG you can use a single filter: <svg height="0" width="0">
<filter id='shadow' color-interpolation-filters="sRGB">
<feDropShadow dx="2" dy="2" stdDeviation="3" flood-opacity="0.5"/>
</filter>
</svg> Found in "Adding Shadows to SVG Icons With CSS and SVG Filters" |
+1 |
2 similar comments
+1 |
+1 |
+1 |
1 similar comment
+1 |
2024 and this is still an issue, many of my recent projects i've been working on have been pretty ui heavy with shadows, blur, and animations, i've solved some of my issues except for lack of shadows in svg |
# Summary Introducing the long-awaited **Filters** in `react-native-svg` 🎉 ### Motivation This PR is the beginning of bringing support of SVG Filters into `react-native-svg`. * **related issues**: This PR series will address the following issues: #150, #176, #635, #883, #994, #996, #1216 * **feature overview**: This PR is a boilerplate for Filters * introducing `Filter` component and `FeColorMatrix` as a start. * It also introduces a new subdirectory called `react-native-svg/filter-image` with a `FilterImage` component. # Usage ## Filter and Fe... Filters are compatible with the web familiar standard, so most things should be compatible out-of-the-box and changes will be limited to using a capital letter as it's component. ### Example ```tsx import React from 'react'; import { FeColorMatrix, Filter, Rect, Svg } from 'react-native-svg'; export default () => { return ( <Svg height="300" width="300"> <Filter id="myFilter"> <FeColorMatrix type="saturate" values="0.2" /> </Filter> <Rect x="0" y="0" width="300" height="300" fill="red" filter="url(#myFilter)" /> </Svg> ); }; ``` ![image](https://github.com/software-mansion/react-native-svg/assets/39670088/c36fb238-95f4-455d-b0aa-2a7d4038b828) ## Filter Image `FilterImage` is a new component that is not strictly related to SVG. Its behavior should be the same as a regular `Image` component from React Native with one exception - the additional prop `filters`, which accepts an array of filters to apply to the image. ### Example ```tsx import React from 'react'; import { StyleSheet } from 'react-native'; import { FilterImage } from 'react-native-svg/filter-image'; const myImage = require('./myImage.jpg'); export default () => { return ( <FilterImage style={styles.image} source={myImage} filters={[ { name: 'colorMatrix', type: 'saturate', values: 0.2 }, { name: 'colorMatrix', type: 'matrix', values: [ 0.2, 0.2, 0.2, 0, 0, 0.2, 0.2, 0.2, 0, 0, 0.2, 0.2, 0.2, 0, 0, 0, 0, 0, 1, 0, ], }, ]} /> ); }; const styles = StyleSheet.create({ image: { width: 200, height: 200, }, }); ``` ![image](https://github.com/software-mansion/react-native-svg/assets/39670088/666ed89f-68d8-491b-b97f-1eef112b7095) ## Test Plan **Example App**: Updated the example app with various filter effects, showcasing real-world usage. ## Compatibility | OS | Implemented | | ------- | :---------: | | iOS | ✅ | | Android | ✅ | ## Checklist - [x] I have tested this on a device and a simulator - [x] I added documentation in `README.md` and `USAGE.md` - [x] I updated the typed files (typescript)
+1 |
We can use this repo react-native-shadow-2 |
Hi!
First of all I would like to say "Thank you" for an amazing library! It's very helpful in RN projects.
Do you have any plans to implement the SVG elements filter or feGaussianBlur ?
They will be very helpful, especially for creating the shadows for shapes.
The text was updated successfully, but these errors were encountered: