Jump to content

Applying SVG Filter to a Canvas (regardless of what image is in the canvas)


AARRGGHHH

Recommended Posts

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

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

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:



<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 by AARRGGHHH
Added content
Link to comment
Share on other sites

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

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

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

xxSVG.jpg

xxTD.jpg

Link to comment
Share on other sites

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

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

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

  • 1 month later...

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! 

  • Like 1
Link to comment
Share on other sites

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

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

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

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...