Jump to content

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


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

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
×
×
  • Create New...