Search code examples
svgcolorsvector-graphicsblendingsvg-filters

Using blending filters (multiply more specifically) using SVG


I have a reference image of the effect that I am trying to achieve using SVG.

Bitmap reference image

In Photoshop the effect can be achieved by using 100% opacity with the blending mode set to 'multiply'

The colors have hex values of:

red: #EA312F, blue: #3A5BA6 and overlapping area: #35111F

I have tried a number of approaches using SVG filters to achieve a similar effect but am struggling to understand how the blending modes calculate the values.

SVG attempts to match original graphic

  1. Original Photoshop bitmap
  2. SVG using only shapes no filters
  3. SVG using multiply filter on vertical bar
  4. SVG using multiply filter and opacity on vertical bar

You can see the SVG code for each of these in this JSBin http://jsbin.com/iPePuvoD/1/edit

I'm really struggling to understand the best approach to match the blue of the vertical bar and the color of the overlapping area.

Each of these shapes i'd also like to animate using a library such as http://snapsvg.io/, so i'm hoping to rely purely on filters, rather than cropping or other operations to achieve the desired results - but am open to suggestions.

Effectively, the SVG for the final attempt (4.) is this:

<svg viewBox="0 0 96 146" version="1.1" id="f-multiply-opacity" preserveAspectRatio="xMinYMin meet">
  <defs>
    <filter id="f_multiply" filterUnits="objectBoundingBox" x="0%" y="0%" width="100%" height="100%">
      <feBlend in="SourceGraphic" mode="multiply"/>
      <feBlend in="SourceGraphic" mode="multiply"/>
    </filter>
  </defs>
  <g id="f_shape">
    <rect x="0" y="0" width="96" height="32" fill="#EA312F" />
    <rect x="0" y="50" width="96" height="32" fill="#EA312F" />
    <rect x="0" y="50" width="32" height="96" opacity="0.8" fill="#3A5BA6" filter="url(#f_multiply)" />
  </g>
</svg>

Would much appreciate some advice on this, I have found some good resources on SVG, but this area still seems quite difficult to get good information on.

Thanks!


Solution

  • This won't work on a number of levels. Feblend takes two inputs not one. What are you blending the sourcegraphic with? If you want to blend with the background you need to use backgroundImage as your in2. If you want to blend with another shape you have to import that shape into the filter with feimage. Next problem BackgroundImage only works in IE at the moment, and feImage only works properly for referenced shapes in Chrome and Safari (Update: you can convert referenced shapes to an inline SVG data-URI and this will work cross browser).

    If you are only using colored rectangles then you can generate them inside the filter using feflood and blend them there. Something like the following:

    <svg x="800px" height="600px" viewBox="0 0 200 100" version="1.1" id="f-multiply-opacity" preserveAspectRatio="xMinYMin meet">
      <defs>
        <filter id="f_multiply" filterUnits="objectBoundingBox" x="0%" y="0%" width="100%" height="100%">
          <feFlood x="0" y="0" width="96" height="32" flood-color="#EA312F" result="a"/>
          <feFlood x="0" y="50" width="96" height="32" flood-color="#EA312F" result="b"/>
          <feFlood rect x="0" y="50" width="32" height="96" flood-opacity="0.8" flood-color="#3A5BA6" result="c"/>
          <feBlend in="a" in2="b" result="ab" mode="multiply"/>
          <feBlend in="ab" in2="c" mode="multiply"/>
         </filter>
      </defs>
      <g id="f_shape">
        <rect filter="url(#f_multiply)" x="0" y="0" width="200" height="200"/>
      </g>
    </svg>
    

    Update: The cross platform way to use shapes within a filter is to encode them as a SVG/XML data URI within a feImage. This is supported cross browser (although it makes the code fairly hard to read.)