0

I have a strange issue I want to mask an image, to keep it simple I tried the svg way as here:

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="217.714" height="321.143" viewBox="0 0 58 85">
  <defs>
    <mask id="a">
      <path d="M22.5 0L45 31.5 22.5 63 0 31.5z" fill="#fff"/>
    </mask>
  </defs>
  <image xlink:href="https://upload.wikimedia.org/wikipedia/commons/9/97/The_Earth_seen_from_Apollo_17.jpg" mask="url(#a)" preserveAspectRatio="xMidYMid slice" width="45" height="63" transform="translate(6.5 14.5)"/>
</svg>

My problem is when I embedded this image it seems to be transparent. When I open it in my browser it works as intended. However when I add it with a img tag like <img src="my.svg"> it takes the dimensions as defined in the svg, but it is transparent.

I tried to upload the svg, but the file type is not supported so I created a gist where it doesn't work too. That is so strange.

It should look like this:

masked earth

Please tell me why this isn't working as expected. If it matter I'm using Firefox 76 on Windows 10.

rekire
  • 47,260
  • 30
  • 167
  • 264
  • Does this answer your question? [Can an SVG included in HTML with an "img" tag have a link to an external image with the "image" tag?](https://stackoverflow.com/questions/11352985/can-an-svg-included-in-html-with-an-img-tag-have-a-link-to-an-external-image-w) – bwoebi May 12 '20 at 12:28

2 Answers2

0

Use an embed tag instead of img. for example:

<embed src="yourfile.svg">

Make sure the path is correct

  • That makes me some headage since I need to change my `X-Frame-Options` headers, for some reasons embed is handeled like an iframe – rekire May 12 '20 at 12:58
0

Yes,
SVG content has CORS restrictions: https://oreillymedia.github.io/Using_SVG/extras/ch10-cors.html

But you can bypass it with some tricks:

  1. Load the IMG URL in Memory with new Image()
  2. transfer it to a CANVAS
  3. extract the Image from the CANVAS to a DataURL String
  4. write full SVG DataURI string (NOT the url to an SVG file) into your hostIMG src

With a W3C standard Custom Element you use it as:

<masked-img src="https://i.picsum.photos/id/21/200/200.jpg" mask="circle"></masked-img>

Note: It doesn't work as an SO snippet below,

JSFiddle at: https://jsfiddle.net/WebComponents/jtys6vn8/

<template id="one">
  <svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' viewBox='0 0 50 50'>
    <mask id="circle"><circle cx='50%' cy='50%' r='20' fill="#fff" /></mask>
    <mask id="diamond">
      <polygon points="25 0 50 25 25 50 0 25" fill="#999" stroke="#f00" stroke-width="5" />
    </mask>
    <image mask='url(#MASK)' x='0' y='0' width='50' height='50' href='IMG' />
  </svg>
</template>

<script>
  customElements.define('masked-img', class extends HTMLElement {
    static get observedAttributes() {
      return ["src", "mask"]; // update whenever these attributes change
    }
    connectedCallback() {
      this.hostIMG = this.appendChild(document.createElement("IMG"));
    }
    attributeChangedCallback() {
      let svgTemplate = document.querySelector(this.getAttribute("svg")).innerHTML;
      let loadIMG = new Image();
      loadIMG.crossOrigin = 'anonymous';//!! required
      loadIMG.onload = () => {
        let canvas = document.createElement("canvas");
        canvas.width = loadIMG.width;
        canvas.height = loadIMG.height;
        canvas.getContext("2d").drawImage(loadIMG, 0, 0);
        this.hostIMG.src = `data:image/svg+xml,` +
          svgTemplate.replace('IMG', canvas.toDataURL("image/png"))
          .replace('MASK', this.getAttribute("mask"))
          .replace(/"/g, "'").replace(/#/g, "%23");// illegal characters in dataURI
      };
      loadIMG.src = this.getAttribute("src");// triggers above onload
    }
  });

</script>

<style>
  img {
    width: 20%;
    background: grey;
  }

</style>

<img src="https://i.picsum.photos/id/21/200/200.jpg">
<masked-img svg="#one" src="https://i.picsum.photos/id/21/200/200.jpg" mask="circle"></masked-img>
<img src="https://i.picsum.photos/id/3/100/100.jpg">
<masked-img svg="#one" src="https://i.picsum.photos/id/3/100/100.jpg" mask="diamond"></masked-img>
Danny '365CSI' Engelman
  • 16,526
  • 2
  • 32
  • 49