0

As stated in the question, you can drag an IMG element from a web page into any other application that accepts it. You can also right-click to select "Save Image As...".

Is there a way to make this work with images (which are dynamically generated)? I had some luck converting the SVGs to data urls and passing them to IMG tags, but this doesn't seem to work on all browsers and is cumbersome.

EDIT: the one answer lead me to consider using Blobs and URL.createObjectURL(). Not sure if this would be less brittle than data urls.

Scott Schafer
  • 487
  • 3
  • 14

3 Answers3

1

By saving the content in a separate file, and adding it into your webpage as the source of an img element:

<img src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/410.svg" />

EDIT: Converting an SVG to a data URL is probably the best way to go. Here are some of data URI's advantages/disadvantages, and here is the official caniuse page for data URIs. I'm not sure what you mean by "this doesn't seem to work on all browsers". Perhaps your encoded image (plus the encoding scheme text) is larger than 32kB (the maximum length of data URIs)?

human bean
  • 847
  • 3
  • 15
  • I should have said that these are dynamically generated SVGs. However, your answer suggested another solution, which is to generate Blobs and then use URL.createObjectURL to around those blobs. – Scott Schafer Nov 18 '22 at 19:46
  • I created a CodeSandbox here: https://codesandbox.io/s/svg-in-different-forms-xpg6v0. There doesn't seem to be an upwards size limit that I've found. The problem was that the library we were using was generating SVGs in a format that didn't work when put in data urls, but only generating them badly on certain browsers. However, the same problematic SVGs would work when directly in the DOM. Very curious. – Scott Schafer Nov 19 '22 at 06:46
1

You can leave the heavy lifting to a native JavaScript Web Component, supported in all modern browsers:

  • load the external SVG as text
  • post process SVG to encode for a DataURI
  • create <img>
  • set DataURI as src
  • !! replace the Web Component itself with the <img>

<style>
  img { height:140px }
</style>

<svg-to-img src="//svg-cdn.github.io/heart.svg"></svg-to-img>
<svg-to-img src="//svg-cdn.github.io/joker-card.svg"></svg-to-img>
<svg-to-img src="//svg-cdn.github.io/svg_circle_spinner.svg"></svg-to-img>

<script>
  customElements.define("svg-to-img", class extends HTMLElement {
    async connectedCallback() {
      let src = this.getAttribute("src");
      let options = { /* fix potential CORS issues, client AND server side */ };
      let svg = await (await fetch(src,options)).text();
      let img = Object.assign(document.createElement("img"), {
        src: "data:image/svg+xml," + svg.replace(/"/g, "'").replace(/#/g, '%23'),
        onload: (e) => console.log("Loaded SVG as IMG", src),
        onerror: (e) => console.error(e)
      });
      this.replaceWith(img);
    }
  })
</script>

Note: Where Browsers accept SVGs without NameSpace; for DataURIs xmlns="http://www.w3.org/2000/svg" is vital on your SVG!

Danny '365CSI' Engelman
  • 16,526
  • 2
  • 32
  • 49
  • This is interesting, and I'm happy to learn about this technique, but at the end of the day: 1) I concluded that IMG tags were in fact the best way to achieve my goal, and that 2) the SVGs had odd things in them (such as xmlns="") that were fine when the SVGs were directly in the DOM but blew up when used as data urls. Your technique is interesting, but my SVGs are generated client side so not really applicable. – Scott Schafer Nov 20 '22 at 19:01
  • Not 100% sure this would work. You could inject your "incorrect" SVG into the DOM, that should fix the NameSpace issues, then read its ``outerHTML`` and inject it as DataURI – Danny '365CSI' Engelman Nov 20 '22 at 21:09
  • Thanks, yeah... I think we originally were doing that, and it did work, but it was deemed to be a "code smell" and removed. Because working code? pfft, who cares about that? ;) Anyway, using a regexp to clean up the crap seems to fix things. – Scott Schafer Nov 21 '22 at 00:01
0

So it looks like using a data url passed to an IMG element is the best way to accomplish my goal, and I ended up using the mini-svg-data-uri library to generate the urls from my (dynamically generated on client side) SVGs.

The real issue seemed to be that the library that generated the SVG for some reason inserted xmlns="" attributes on some browsers, no idea why. This wasn't a problem in any browser when the SVG was directly in the DOM (as an <svg> element), but fails when the problematic SVGs are used as data urls.

https://codesandbox.io/s/svg-in-different-forms-xpg6v0

Scott Schafer
  • 487
  • 3
  • 14