AARRGGHHH Posted December 1, 2020 Share Posted December 1, 2020 I've seen this (and similar) code used to apply an SVG filter to an image. How do I use this code to apply an SVG filter to a canvas? The canvas' content may change often. <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <defs> <filter id="darkGreen"> <feColorMatrix type="matrix" values="0 0 0 0 0 0 0.5 0 0 0 0 0 0 0 0 0 0 0 0 1" /> </filter> </defs> <image xlink:href="(url to image)" width="" height="" filter="url(#darkGreen)" /> </svg> Thank you Link to comment Share on other sites More sharing options...
Ingolme Posted December 2, 2020 Share Posted December 2, 2020 SVG does not have a <canvas> element. The <foreignObject> tag might work to embed an HTML5 <canvas> element but I'm not sure how well <foreignObject> works. Instead of trying to embed the <canvas> in an SVG document, you could put the SVG code in a separate file and load its filter with the CSS filter property. Link to comment Share on other sites More sharing options...
AARRGGHHH Posted December 3, 2020 Author Share Posted December 3, 2020 (edited) On 12/1/2020 at 9:42 PM, Ingolme said: Instead of trying to embed the <canvas> in an SVG document, you could put the SVG code in a separate file and load its filter with the CSS filter property. Thank you for the reply! SO what you have in mind is: <script> svgfile() </script> And svgfile() is a function in an external file. How do I get the main page to load the filter from the external page? One potential complication: There will also be CSS filters working in the main page. How can I get the .filter property to accept both CSS filters from the main page, plus SVG filter(s) from the external page? Thank you! PS: On this page https://www.w3.org/TR/SVG2/embedded.html I found this: Which would seem to imply that a canvas tag can be placed within an svg tag. Quote 12.4. HTML elements in SVG subtrees The following HTML elements render when included in an SVG subtree as a child of a container element and when using the HTML namespace: 'video' 'audio' 'iframe' 'canvas' <svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> <html:video src="file.mp4" controls="controls"> </html:video> </svg> They gave a simple example for video (above), but not for canvas. Based on that example, I tried this: <canvas id="cSave" width="400" height="200" onclick="clickPreview()" style="position:relative; max-width:100%;"></canvas> <svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> <defs> <filter id="darkGreen"> <feColorMatrix type="matrix" values="0 0 0 0 0 0 0.5 0 0 0 0 0 0 0 0 0 0 0 0 1" /> </filter> </defs> <html:canvas name="cSave"> </html:canvas> </svg> Which should create a dark Green color cast. But all I got was an empty canvas. Do you think this <svg> inside <canvas> can be made to work? Thanks again! Edited December 3, 2020 by AARRGGHHH Added content Link to comment Share on other sites More sharing options...
Ingolme Posted December 6, 2020 Share Posted December 6, 2020 No, it is much simpler than that. Save your SVG filter in a .svg file, then apply the filter to any object using the CSS filter property: <style> #myCanvas { filter: url("file.svg#darkGreen"); } </style> ... <canvas id="myCanvas"></canvas> Link to comment Share on other sites More sharing options...
AARRGGHHH Posted December 10, 2020 Author Share Posted December 10, 2020 I will try that, thank you VERY much. Will it be possible manipulate the SVG filter's values (for example, a feColorMatrix or feConvolver filter's matrix values) with JavaScript in my HTML page? Thanks again! Link to comment Share on other sites More sharing options...
Ingolme Posted December 10, 2020 Share Posted December 10, 2020 Unfortunately, you can't modify it with Javascript if it is being loaded from another file. To do that, since canvas can be embedded in SVG, that's probably the best way to do it. Just a tweak to your previous code: <svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> <defs> <filter id="darkGreen"> <feColorMatrix type="matrix" values="0 0 0 0 0 0 0.5 0 0 0 0 0 0 0 0 0 0 0 0 1" /> </filter> </defs> <html:canvas id="cSave" width="400" height="200" onclick="clickPreview()" style="position:relative; max-width:100%;"></html:canvas> </svg> In this way, you can access the filter as a DOM element and change its values. Link to comment Share on other sites More sharing options...
AARRGGHHH Posted December 10, 2020 Author Share Posted December 10, 2020 Thank you so much. Unfortunately, I'm still getting something wrong. The canvas is showing up first, as it should. The SVG is showing up under the canvas. I tried wrapping it in <foreignObject> tags, but that did not help. Also, the table that the canvas should exist in is outside of the canvas. I have a feeling I missed something simple. ... <td id="tdSave" style="width:100%; border-style:none;"> <!-- START NEW SVG CODE --> <svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"> <defs> <filter id="xPurple"> <feColorMatrix type="matrix" values="2 0 0 0 0 0 1 0 0 0 0 0 2 0 0 0 0 0 0 1" /> </filter> </defs> <foreignObject> <html:canvas id="cSave" width="400" height="200" onclick="clickPreview()" style="position:relative; max-width:100%;"> </html:canvas> </foreignObject> </svg> <!-- END NEW SVG Code --> </td> ... Screen Shots (hope this helps) are below. Many Thanks !!! Link to comment Share on other sites More sharing options...
AARRGGHHH Posted December 10, 2020 Author Share Posted December 10, 2020 Just a thought, it's almost as though there's nothing "connecting" the table data and canvas to the filter. But I could be way off on that. Link to comment Share on other sites More sharing options...
Ingolme Posted December 11, 2020 Share Posted December 11, 2020 Oh, the filter needs to be applied using the svg filter attribute. I'm not entirely sure what the best way to do it is, I would have to do experiments. Either give a filter attribute to the <html:canvas> element or give it to the <foreignObject> tag. Either this: <html:canvas filter="url(#xPurple)" ... ... > or this: <foreignObject filter="url(#xPurple)"> ... ... If the <foreignObject> tag necessary? Link to comment Share on other sites More sharing options...
AARRGGHHH Posted December 11, 2020 Author Share Posted December 11, 2020 Thank you once again! Neither worked, but I'm still trying different things to see if I can make it work. I've read <foreignObject> is needed, I'm not really sure. What I'll ultimately be doing is combining CSS and SVG filters to make changes to an image. This uh ... this can be done, right? I would think (hope) that canvas.filter will hold all the applied filters, not just the multiple CSS filters. Please let me know if you have any other thoughts on applying the svg filter attribute. Thanks again! Link to comment Share on other sites More sharing options...
Ingolme Posted December 12, 2020 Share Posted December 12, 2020 I think it may be possible to use embedded SVG filters in the CSS rule. Have the SVG embedded anywhere in your document, but use the CSS rule on the <canvas> element. The same as the original solution, but instead of the SVG being in a different file, it is within the same document: <style> #myCanvas { filter: url("#darkGreen"); } </style> ... <svg> <defs> <filter id="darkGreen"> ... </filter> </defs> </svg> ... <canvas id="myCanvas"></canvas> With this setup (if it works), you will be able to edit the SVG filter with Javascript while also applying the filter to a <canvas> element. Link to comment Share on other sites More sharing options...
AARRGGHHH Posted January 17, 2021 Author Share Posted January 17, 2021 Hi Ingolme Thank you once again! I was away for a while due to the holidays and an illness in the family. For some reason, the SVG filter is not being applied to the canvas cPreview, but is being applied to the canvas cSave. Do you have any thoughts on why this may be happening? Here's my code: <style> #cSave { filter: url("#svgCOLOR"); } #cPreview { filter: url("#svgCOLOR"); } </style> <!-- SVG Declaration --> <svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml" width="2" height="1"> <defs> <filter id="svgCOLOR"> <!-- Matrix values will eventually be adjustable using a range slider control --> <feColorMatrix type="matrix" values="2 0 0 0 0 0 1 0 0 0 0 0 2 0 0 0 0 0 0 1" /> </filter> </defs> </svg> <!-- CANVAS cPreview --> <canvas id="cPreview" width="2" height="1" style="position:relative; max-width:100%;"></canvas> <!-- CANVAS cSave --> <canvas id="cSave" width="2" height="1" onclick="clickPreview()" style="position:relative; max-width:100%;"></canvas> Thank you! 1 Link to comment Share on other sites More sharing options...
Ingolme Posted January 18, 2021 Share Posted January 18, 2021 I can't see any obvious reason in the code that you have shown here. As your code is right now, for me both canvas look the same. Perhaps with a real use case example I could see where the problem is. Link to comment Share on other sites More sharing options...
AARRGGHHH Posted January 18, 2021 Author Share Posted January 18, 2021 I'm not sure what you mean by a "use case" example. Please let me know! Link to comment Share on other sites More sharing options...
Ingolme Posted January 19, 2021 Share Posted January 19, 2021 I mean a block of code that will run on its own which displays the problem. I need to be able to see the problem happening on my computer in order to find out what is wrong. Link to comment Share on other sites More sharing options...
AARRGGHHH Posted January 21, 2021 Author Share Posted January 21, 2021 I'll certainly post that if needed, but I think I found the problem, after stepping through all 700+ lines of code. This line is blocking the SVG filter: if (document.getElementById("cPreview") != null) document.getElementById("cPreview").style.WebkitFilter = "brightness(" + parseInt(percentB) + "%)" + " contrast(" + parseInt(percentC) + "%)" + " hue-rotate(" + parseInt(degrees) + "deg)" + " saturate(" + parseInt(percentS) + "%)"; That line was only there for backwards compatibility with older browsers. Commenting that line blocks the CSS filters (brightness, contrast, etc..) but allows the SVG to work. If I change style.WebKitFilter to style.filter, the CSS filters work, but the SVG stops working. So the question becomes how do I add the SVG filter to that line of code? I tried this with no luck: if (document.getElementById("cPreview") != null) document.getElementById("cPreview").style.filter = "brightness(" + parseInt(percentB) + "%)" + " contrast(" + parseInt(percentC) + "%)" + " svgCOLOR(value)" + " saturate(" + parseInt(percentS) + "%)"; Apparently "svgCOLOR(value)" is not the proper way to reference the SVG filter. So... how do I add the SVG filter to that line of code? Thank you! Link to comment Share on other sites More sharing options...
AARRGGHHH Posted January 22, 2021 Author Share Posted January 22, 2021 Just to make it more painful: I fixed it last night. Then looked at it half asleep and broke it. And I can't remember how I fixed it. Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now