9

svg image

I have an SVG image like this. I would like to invert it, such that everything that is black becomes transparent, and everything that is transparent becomes black. So the result would be a black square with a transparent, square shaped 'hole' in the middle. How can I achieve this?

Code for the svg:

<svg
   xmlns="http://www.w3.org/2000/svg"
   viewBox="0 0 99.999997 99.999997"
   height="100"
   width="100">
  <g
     transform="translate(0,-952.36223)"
  >
    <path
       d="M 50.000001,954.80939 65.450848,986.11624 100,991.13652 74.999998,1015.5055 80.901699,1049.915 50,1033.6691 19.098298,1049.915 25.000001,1015.5055 -1.2134336e-6,991.13652 34.549151,986.11624 Z"
       style="opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:22.67716599;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
  </g>
</svg>

2 Answers 2

8

Use the path as a mask like below:

body {
  background:pink;
}
<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg"
   viewBox="0 0 99.999997 99.999997">
  <defs>
    <mask id="hole">
      <rect width="100%" height="100%" fill="white"/>
      <path transform="translate(0,-952.36223)"
       d="M 50.000001,954.80939 65.450848,986.11624 100,991.13652 74.999998,1015.5055 80.901699,1049.915 50,1033.6691 19.098298,1049.915 25.000001,1015.5055 -1.2134336e-6,991.13652 34.549151,986.11624 Z"
       fill="black" />
    </mask>
  </defs>
  <rect fill="black" width="100%" height="100%" mask="url(#hole)" />
</svg>

2
  • @Kaiido why? they simply need to change the fill of the rect to white Commented Apr 9, 2019 at 6:24
  • I was talking about the original path but nevermind actually
    – Kaiido
    Commented Apr 9, 2019 at 6:26
2

The original answer showed an approach using the feFuncA primitive - GetSelf pointed out below that it wasn't working due to browser bugs).

Another approach that works is to invert the alpha channel using a feColorMatrix filter. Updated code below. Note this still won't work on fully transparent colored shapes in Chrome since it seems to discard any color channel values for shapes with opacity below 0.005.

<svg
   xmlns="http://www.w3.org/2000/svg"
   viewBox="0 0 99.999997 99.999997"
   height="100"
   width="100">
  <defs>
    <filter id="invert-alpha">
      <feColorMatrix type="matrix" values="1 0 0 0 0 
                                       0 1 0 0 0 
                                       0 0 1 0 0
                                       0 0 0 -1 1"/>
</filter>
  </defs>
  <g
     transform="translate(0,-952.36223)" filter="url(#invert-alpha)"
  >
    <path
       d="M 50.000001,954.80939 65.450848,986.11624 100,991.13652 74.999998,1015.5055 80.901699,1049.915 50,1033.6691 19.098298,1049.915 25.000001,1015.5055 -1.2134336e-6,991.13652 34.549151,986.11624 Z"
       style="opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:22.67716599;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
  </g>
</svg>

2
  • 1
    This does not invert the alpha channel. It just turns completely transparent pixels into opaque and completely opaque intro transparent. Semi-transparent pixels are left unchanged.
    – GetFree
    Commented Aug 19, 2019 at 2:55
  • Ah - I'm pretty sure this used to work, but in fact, Firefox is not rendering this correctly at all. And Chrome has a bug inverting zero opacity shapes (it discards the color channel values). I have filed bugs against this on Bugzilla and Chromium. Thanks! Commented Aug 20, 2019 at 2:05

Not the answer you're looking for? Browse other questions tagged or ask your own question.