Filter effects

Internet Explorer 10 and Windows apps using JavaScript introduce support for Scalable Vector Graphics (SVG) filter effects. SVG filters enable you to manipulate graphics—similar to what you might do with an application such as Adobe Photoshop—directly in the browser. Consider the following SVG graphic.

Using SVG filter elements, this simple graphic can easily be transformed into a much more visually appealing form.

Both of these images were taken directly from the filter example from the W3C SVG specification. Let's take a deep dive into this canonical example. The first graphic is simply two SVG paths and the text "SVG", and is rendered with the following markup.

<g>
  <path fill="none" stroke="#D90000" stroke-width="10" 
        d="M50,90 C0,90 0,30 50,30 L150,30 C200,30 200,90 150,90 z" /> 
        <!-- Outer hollow area. -->
  <path fill="#D90000" 
        d="M60,80 C30,80 30,40 60,40 L140,40 C170,40 170,80 140,80 z" /> 
        <!-- Inner filled arena. -->
  <g fill="#FFFFFF" stroke="black" font-size="45" font-family="Verdana" >
    <text x="52" y="76">SVG</text> 
    <!-- The text "SVG". -->
  </g>
</g>

To apply an SVG filter effect to this <g> group, define a filter, name it (such as MyFilter), and apply it to the group as follows.

<g filter="url(#MyFilter)">
  <path fill="none" stroke="#D90000" stroke-width="10" 
        d="M50,90 C0,90 0,30 50,30 L150,30 C200,30 200,90 150,90 z" /> <!-- Outer hollow arena. -->
  <path fill="#D90000" 
        d="M60,80 C30,80 30,40 60,40 L140,40 C170,40 170,80 140,80 z" /> <!-- Inner filled arena. -->
  <g fill="#FFFFFF" stroke="black" font-size="45" font-family="Verdana" >
    <text x="52" y="76">SVG</text> <!-- The "SVG" text. -->
  </g>
</g>

To understand the filter that was used to create the effect in the second image, let's take a look at the complete example. Be aware that this example has been modified slightly from the original to work within an HTML5 document (as opposed to an SVG document).

<!DOCTYPE html>
<html><head>
  <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
  <title>Example filters01.svg - introducing filter effects</title>
</head><body>
  <svg width="7.5cm" height="5cm" viewBox="0 0 200 120">
    <desc>An example that combines multiple filter primitives
          to produce a 3D lighting effect on a graphic. The graphic contains the
          string "SVG" sitting on top of an oval filled in red
          and surrounded by an oval outlined in red.</desc>
    <defs>
      <filter id="MyFilter" filterUnits="userSpaceOnUse">
        <feGaussianBlur in="SourceAlpha" stdDeviation="4" result="blur"/>
        <feOffset in="blur" dx="4" dy="4" result="offsetBlur"/>
        <feSpecularLighting in="blur" surfaceScale="5" specularConstant=".75" 
                            specularExponent="20" lighting-color="#bbbbbb"  
                            result="specOut">
          <fePointLight x="-5000" y="-10000" z="20000"/>
        </feSpecularLighting>
        <feComposite in="specOut" in2="SourceAlpha" operator="in" result="specOut"/>
        <feComposite in="SourceGraphic" in2="specOut" operator="arithmetic" 
                     k1="0" k2="1" k3="1" k4="0" result="litPaint"/>
        <feMerge>
          <feMergeNode in="offsetBlur"/>
          <feMergeNode in="litPaint"/>
        </feMerge>
      </filter>
    </defs>
    <rect x="1" y="1" width="198" height="118" fill="#888888" stroke="blue" />   
    <g filter="url(#MyFilter)" >
      <g>
        <path fill="none" stroke="#D90000" stroke-width="10" 
              d="M50,90 C0,90 0,30 50,30 L150,30 C200,30 200,90 150,90 z" />
        <path fill="#D90000" 
              d="M60,80 C30,80 30,40 60,40 L140,40 C170,40 170,80 140,80 z" />
        <g fill="#FFFFFF" stroke="black" font-size="45" font-family="Verdana" >
          <text x="52" y="76">SVG</text>
        </g>
      </g>
    </g>
  </svg>
</body></html>

First, we create an SVG viewport that has appropriate user units and size.

<svg width="7.5cm" height="5cm" viewBox="0 0 200 120">

Next we name the filter using the id attribute.

<filter id="MyFilter" filterUnits="userSpaceOnUse">

This filter consists of six numbered filter primitives (five of which are unique):

1. feGaussianBlur

2. feOffset

3. feSpecularLighting

4. feComposite

5. feComposite

6. feMerge

Filter primitives can be chained together to create very complex effects by allowing the output of one primitive to become the input of another. For example, the output of feGaussianBlur ( result="blur") becomes the input to feOffset (in="blur").

Be aware that the keyword SourceGraphic represents the original image that the filter is applied to. In this case, the source image is everything within the <g> element.

<g filter="url(#MyFilter)" >
  <g>
    <path fill="none" stroke="#D90000" stroke-width="10" 
          d="M50,90 C0,90 0,30 50,30 L150,30 C200,30 200,90 150,90 z" />
    <path fill="#D90000" 
          d="M60,80 C30,80 30,40 60,40 L140,40 C170,40 170,80 140,80 z" />
    <g fill="#FFFFFF" stroke="black" font-size="45" font-family="Verdana" >
      <text x="52" y="76">SVG</text>
    </g>
  </g>
</g>

Additionally, the keyword SourceAlpha represents the alpha channel of the source graphic. The alpha channel typically represents transparency information associated with a graphic. This component of the source graphic is what is fed into the first filter primitive, feGaussianBlur, as shown in the following flowchart.

The six major steps for the filter are numbered in the previous flowchart, and are explained here:

  1. Filter primitive feGaussianBlur takes input SourceAlpha, which is the alpha channel of the source graphic. The result is stored in a temporary buffer named "blur". Be aware that blur is used as input to both filter primitives #2 and #3.
  2. Filter primitive feOffset takes buffer blur, shifts the result in the positive x- and y-direction by 4 pixels, and creates a new buffer named "offsetBlur". This buffer is used later to create a drop shadow effect.
  3. Filter primitive feSpecularLighting, uses buffer "blur" as a model of a surface elevation and generates a lighting effect from a single point source. The result is stored in buffer "specOut".
  4. Filter primitive feComposite masks out the result of filter primitive #3 by the original source graphic's alpha channel so that the intermediate result is no bigger than the original source graphic. The buffer name "specOut" is used again to store the result.
  5. Filter primitive feComposite combines the result of the specular lighting with the original source graphic. The result is placed in buffer "litPaint".
  6. Filter primitive feMerge combines two layers together. The lower consists of the drop shadow result from filter primitive #2. The upper layer consists of the specular lighting result from filter primitive #5. If this seems backwards, recall that the last SVG element is rendered "on top of" all prior rendered SVG elements.

As the previous example shows, SVG filters can be used to easily create complex graphics in the browser. And because SVG filters can be controlled through JavaScript, they provide the ability for web developers to create rich, graphics-oriented applications and user interfaces that provide end users with smooth, fluid, and animated (via JavaScript) experiences.

API Reference

SVG Element Reference (filter effects begin with "fe")

Samples and tutorials

SVG Filter effects sample

How to blend two raster images using SVG filters

Internet Explorer Test Drive demos

Hands On: SVG Filter Effects

IEBlog posts

SVG Filter Effects in IE10

Specification

Scalable Vector Graphics (SVG) 1.1 (Second Edition): Section 15