bongbang
bongbang

Reputation: 1712

Inverting SVG image mask

In my application, it is more convenient for me to use an image to mask SVG shapes rather than the other way round. (The desired multi-color overlays effects can be achieved either way.) The problem is, when I use a normal (grayscale) image as the mask, the result looks like a negative film. Is there an SVG attribute or clever JS/D3 trick that I can use to tell the browser to invert its masking protocol or am I stuck with converting the images myself (which may end up being less convenient than doing it the other way)?

Update Minimal example:

<!DOCTYPE html>
<title>Image mask</title>

<script type="text/javascript"
  src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js">
</script>
<body>
<div>
<button>toggle</button>
</div>
</body>
<script>
var width = 194,
	height = 240;
	maskWidth = 30;
var svg = d3.select('body').append('svg')
	.attr('height', 500);

var myMask = svg.insert('mask', ':first-child')
	.attr('id', 'image_mask');

var marilyn = myMask.append('image')
	.attr('width', width)
	.attr('height', height)
	.attr('xlink:href', "https://upload.wikimedia.org/wikipedia/commons/thumb/8/8d/Marilyn_Monroe_photo_pose_Seven_Year_Itch.jpg/194px-Marilyn_Monroe_photo_pose_Seven_Year_Itch.jpg");

var positive = svg.append('rect')
	.attr('width',maskWidth)
	.attr('height', height)
	.attr('fill', 'red')
	.attr('mask', 'url(#image_mask)');

var negative = svg.append('rect')
	.attr('x', maskWidth)
	.attr('width', width - maskWidth)
	.attr('height', height)
	.attr('fill', 'green')
	.attr('mask', 'url(#image_mask)');
	
var toggle = false;
d3.select('button').on('click', function() {
	toggle = !toggle;
	positive.transition()
		.attr('height', toggle ? height/2 : height);
});

</script>

Upvotes: 1

Views: 1846

Answers (1)

Paul LeBeau
Paul LeBeau

Reputation: 101820

You'll need to use a <filter> to invert the image in your mask.

<svg height="500" xmlns:xlink="http://www.w3.org/1999/xlink" >
  <defs>
    <filter id="invert">
      <feComponentTransfer>
        <feFuncR type="table" tableValues="1 0"/>
        <feFuncG type="table" tableValues="1 0"/>
        <feFuncB type="table" tableValues="1 0"/>
      </feComponentTransfer>
    </filter> 
    <mask id="image_mask">
      <image width="194" height="240" xlink:href="https://upload.wikimedia.org/wikipedia/commons/thumb/8/8d/Marilyn_Monroe_photo_pose_Seven_Year_Itch.jpg/194px-Marilyn_Monroe_photo_pose_Seven_Year_Itch.jpg"
             filter="url(#invert)"/>
    </mask>
  </defs>
  
  <rect width="30" height="120" fill="red" mask="url(#image_mask)"/>
  <rect x="30" width="164" height="240" fill="green" mask="url(#image_mask)"/>
</svg>

Upvotes: 4

Related Questions