Search code examples
imagesvgtransparencyalphasvg-filters

Apply noise to image with transparency by use of SVG filters


I'm trying to apply a noise effect to an image, however, I struggle to maintain the transparency. Here's a fiddle to illustrate:

https://jsfiddle.net/t1aeyqfu/

#noisy {
  filter: url(#noise);
}

#filter {
  visibility: hidden;
}
<body style="background-color: #aca">
  <img src="https://i.postimg.cc/pr61qLqk/flower.png" id="noisy">
  <svg id="filter">
    <filter id="noise">
      <feTurbulence baseFrequency="0.60" xresult="colorNoise" />
      <feColorMatrix in="colorNoise" type="matrix" values=".33 .33 .33 0 0 .33 .33 .33 0 0 .33 .33 .33 0 0 0 0 0 1 0" result="monoNoise" />
      <feBlend in="SourceGraphic" in2="monoNoise" mode="multiply" />
    </filter>
  </svg>

</body>

My goal is to apply the noise effect only to the parts of the image which are not transparent. (In the above example: No noise outside of the blue flower.)

I got somewhat close using feComposite with out operator, but then the noise inherits the transparency. Applying the SourceAlpha to the result might help, but I can't figure out how.

Thanks for your hints!


Solution

  • Just clip the noise to the original shape by adding a feComposite/in. The rest stays the same.

    #noisy {
      filter: url(#noise);
    }
    
    #filter {
      visibility: hidden;
    }
    <body style="background-color: #aca">
      <img src="https://i.postimg.cc/pr61qLqk/flower.png" id="noisy">
      <svg id="filter">
        <filter id="noise">
          <feTurbulence baseFrequency="0.60" xresult="colorNoise" />
          <feColorMatrix in="colorNoise" type="matrix" values=".33 .33 .33 0 0 .33 .33 .33 0 0 .33 .33 .33 0 0 0 0 0 1 0"/>
          <feComposite operator="in" in2="SourceGraphic" result="monoNoise"/>
          <feBlend in="SourceGraphic" in2="monoNoise" mode="multiply" />
        </filter>
      </svg>
    
    </body>