Add Warping Or Ripping Effects With The feDisplacementMap Filter Primitive

If you like to play around with warping effects in your favorite graphic editor, you might find you you enjoy experimenting with the feDisplacementMap filter.

For a little over a month, I’ve been walking through different filter primitives. I began with feColorMatrix and feComponentTransfer for working with color and then moved on to lighting effects with feDiffuseLighting and feSpecularLighting.

Last week I looked at a couple of primitives, feMorphology and feTurbulence that didn’t quite fit into any easily defined category. Today I want to add another, the feDisplacementMap primitive. Next week I’ll walk feConvolveMatrix.

The feDisplacementMap Filter Primitive

The feDisplacementMap primitive uses color values from one image to determine how much to move or displace the pixels in another. It can be used to create warping, ripping, and similar types of effects.

The two images are set as the values of the in and in2 attributes of the feDispacementMap primitive.

  • in—This is the image that will be displaced
  • in2—This is the image used to displace the image defined by in.

Note that the same image can be used to displace itself so in and in2 can refer to the same image. Also by image, I mean any SVG element.

The transformation performed is the following.

[code type=html]
P'(x,y) <- P( x + scale * (XC(x,y) – .5), y + scale * (YC(x,y) – .5))

P(x,y) is the input image (in), P’(x,y) is the final result, and XC(x,y) and YC(x,y) are components of the in2 image.

Don’t worry. You won’t work directly with the formula, but I thought I’d show it to you so you can see what’s going on behind the scenes.

In addition to in, in2, and the other attributes common to all filter primitives, feDisplacementMap takes three more attributes, scale, xChannelSelector, and yChannelSelector

  • scale = “<number>”—The displacement scale factor. It determines how far to displace the pixels of the “in” image. 0 is the default
  • xChannelSelector = “R | G | B | A”—Indicates which channel from “in2” will be used to use to displace the pixels in “in” along the x-axis. The default is A or the alpha channel.
  • yChannelSelector = “R | G | B | A”—Indicates which channel from “in2” will be used to use to displace the pixels in “in” along the y-axis. The default is A or the alpha channel.

Here’s an example where I used an image of Strawberry Fields, that I’ve used throughout this series, to displace the pixels in SVG text.

I include the image using the feImage filter primitive, give it a result of “out” which I then feed into the feDisplacementMap primitive as the in2 image. The in image is the SourceGraphic, in this case a text element. I chose the Blue (B) and Green (G) channels as the xChannelSelector and yChannelSelector and set the scale to 9.

[code type=html]
<svg width="100%" height="220" style="outline: 1px solid red">
<filter id="squiggly">
<feImage xlink:href="" result="out" width="660" height="495" />
<feDisplacementMap id="displacement" in="SourceGraphic" in2="out" scale="9" xChannelSelector="B" yChannelSelector="G" />

<g font-size="3em">
<text x="225" y="75"">Squiggly</text>
<text x="225" y="150" filter="url(#squiggly)">Squiggly</text>

The result is a squiggly effect applied to the text.


Here’s another example where I used the Strawberry Fields image to displace itself. I increased the scale to make the effect more apparent and chose different RGBA components (G and R) for the two channel selectors.

[code type=html]
<svg width="100%" height="495" style="outline: 1px solid red">
<filter id="strawberry">
<feImage xlink:href="" result="out" width="660" height="495" x="0" y="0" />
<feDisplacementMap id="displacement" in="SourceGraphic" in2="out" scale="99" xChannelSelector="G" yChannelSelector="R"/>

<image xlink:href="" width="100%" height="495" filter=url(#strawberry) x="0" y="0" />

Here’s the result.

Aside from the scale, where the greater the scale, the more displacement occurs, I’m not sure there’s any way to know in advance how the pixels will be displaced. This seems to be more of a trial and error primitive, where you play around with different values, see what happens, and stop when you’re happy with the results.

Here’s one last example where I used a linear gradient to displace the same image of Strawberry Fields. I created a 4 stop linear gradient with color changes from red to green to blue and back to red. I filled a 400 by 500 rectangle with the gradient and then included the rectangle inside an feImage primitive inside the filter, which becomes the value of in2.

[code type=html]
<svg width="100%" height="495" style="outline: 1px solid red">
<linearGradient id="linear">
<stop offset="0" stop-color="#ff0000" />
<stop offset="0.33" stop-color="#00ff00"/>
<stop offset="0.67" stop-color="#0000ff"/>
<stop offset="1" stop-color="#ff0000" />

<rect id="rectangle" x="0" y="0" width="400" height="500"

<filter id="gradient">
<feImage xlink:href="#rectangle" result="grad"/>
<feDisplacementMap id="displacement" in="SourceGraphic" in2="grad" scale="99" xChannelSelector="B" yChannelSelector="G" />

<image xlink:href="" width="100%" height="495" filter=url(#gradient) x="0" y="0"/>

The result is a warping effect on the original image.

Again, I’d like to tell you I knew in advance what would happen with each of these examples, but it was more trial and error on my part. I tried something and experimented with the values to see what I could create.

As I’ve done a few times in this series, I’ll encourage you to do the same. Try something and see what happens. Then play around and see what you can do.

Closing Thoughts

The feDisplacementMap primitive is another that I think is relatively easy to work with even if you don’t quite know what will happen in advance when you use it.

Hopefully the examples here show that there’s a wide range of potential effects you can create with this primitive.

Next week I’ll talk about the last primitive, feConvolveMatrix. The name might not mean much, but you can use this primitive to add embossing, beveling, and other types of effects.

« »

Download a free sample from my book, Design Fundamentals.


  1. Hi, I’ve been trying to figure out how feImage + feDisplacementMap works, and why these examples are now only working in Safari.

    I’m guessing this might be related to the same security-related issues that prevent BackgroundImage from being used as a filter input.

    The good news is that an feImage with inline data URI will work when passed into feDisplacementMap, but with caveats.

    Inline SVG works in Chrome, but not Firefox (Firefox bug #455986).

    If you use a different image format for your feImage, like PNG, then it does actually work in Chrome and Firefox.

Leave a Reply

Your email address will not be published. Required fields are marked *