Save inline SVG as JPEG/PNG/SVG

前端 未结 4 775
礼貌的吻别
礼貌的吻别 2020-11-28 04:13

I have an inline SVG in my html, and I need to be able to save this as either a JPEG, PNG or SVG.

I have tried a few different methods with converting the SVG to can

相关标签:
4条回答
  • 2020-11-28 04:24

    Nowadays this is pretty simple.

    The basic idea is:

    1. svg to canvas
    2. canvas to dataUrl
    3. trigger download from dataUrl

    it actually works outside of stackoverflow snippet

    var btn = document.querySelector('button');
    var svg = document.querySelector('svg');
    var canvas = document.querySelector('canvas');
    
    function triggerDownload (imgURI) {
      var evt = new MouseEvent('click', {
        view: window,
        bubbles: false,
        cancelable: true
      });
    
      var a = document.createElement('a');
      a.setAttribute('download', 'MY_COOL_IMAGE.png');
      a.setAttribute('href', imgURI);
      a.setAttribute('target', '_blank');
    
      a.dispatchEvent(evt);
    }
    
    btn.addEventListener('click', function () {
      var canvas = document.getElementById('canvas');
      var ctx = canvas.getContext('2d');
      var data = (new XMLSerializer()).serializeToString(svg);
      var DOMURL = window.URL || window.webkitURL || window;
    
      var img = new Image();
      var svgBlob = new Blob([data], {type: 'image/svg+xml;charset=utf-8'});
      var url = DOMURL.createObjectURL(svgBlob);
    
      img.onload = function () {
        ctx.drawImage(img, 0, 0);
        DOMURL.revokeObjectURL(url);
    
        var imgURI = canvas
            .toDataURL('image/png')
            .replace('image/png', 'image/octet-stream');
    
        triggerDownload(imgURI);
      };
    
      img.src = url;
    });
    <button>svg to png</button>
    
    <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="200" height="200">
      <rect x="10" y="10" width="50" height="50" />
      <text x="0" y="100">Look, i'm cool</text>
    </svg>
    
    <canvas id="canvas"></canvas>

    Regarding the downloading part, you can set up a filename and etc etc (although not in this example). Some days ago i answered a question on how to download a specific portion of HTML from the given page. It might be useful regarding the downloading part: https://stackoverflow.com/a/28087280/2178180

    update: now letting you specify the filename

    0 讨论(0)
  • 2020-11-28 04:26

    Working off @CiroCosta. 1 option if you are having trouble exporting an element you could just draw the image to the canvas before drawing the svg image

    btn.addEventListener('click', function () {
      var canvas = document.getElementById('canvas');
      var ctx = canvas.getContext('2d');
      var data = (new XMLSerializer()).serializeToString(svg);
      var DOMURL = window.URL || window.webkitURL || window;
    
      // get the raw image from the DOM
      var rawImage = document.getElementById('yourimageID');
      var img = new Image();
      var svgBlob = new Blob([data], {type: 'image/svg+xml;charset=utf-8'});
      var url = DOMURL.createObjectURL(svgBlob);
    
      img.onload = function () {
        ctx.drawImage(rawImage, 0, 0);
        ctx.drawImage(img, 0, 0);
        DOMURL.revokeObjectURL(url);
    
        var imgURI = canvas
          .toDataURL('image/png')
          .replace('image/png', 'image/octet-stream');
    
        triggerDownload(imgURI);
      };
    
      img.src = url;
    });
    

    Worked for me but only for png and jpeg. SVG files still only display inline elements and not tags

    EDIT: The way you create an svg like this is actually by converting the image tag into Base64 and the setting that as the xlink:href in the image attributes like this:

    <image id="crop" width="725" height="1764" xlink:href="data:image/png;base64,iVBORw0KGgo ... " />
    

    and then triggering the download on the whole svg url like this:

    btn.addEventListener('click', function () {
      var canvas = document.getElementById('canvas');
      var ctx = canvas.getContext('2d');
      var data = (new XMLSerializer()).serializeToString(svg);
      var DOMURL = window.URL || window.webkitURL || window;
    
      var rawImage = document.getElementById('yourimageID');
      var img = new Image();
      var svgBlob = new Blob([data], {type: 'image/svg+xml;charset=utf-8'});
      var url = DOMURL.createObjectURL(svgBlob);
    
      img.onload = function () {
        ctx.drawImage(img, 0, 0);
    
        triggerDownload(url);
        DOMURL.revokeObjectURL(url);
      }
    };
    

    you can convert pngs like this here:

    function getDataUri(url, callback) {
      var image = new Image();
    
      image.onload = function () {
        var canvas = document.createElement('canvas');
        canvas.width = this.naturalWidth; // or 'width' if you want a special/scaled size
        canvas.height = this.naturalHeight; // or 'height' if you want a special/scaled size
    
        canvas.getContext('2d').drawImage(this, 0, 0);
    
        // Get raw image data
        callback(canvas.toDataURL('image/png').replace(/^data:image\/(png|jpg);base64,/, ''));
    
        // ... or get as Data URI
        callback(canvas.toDataURL('image/png'));
      };
    
      image.src = url;
    }
    

    then setting the attribute

    getDataUri('localImagepath', function (dataUri) {
      image.setAttribute('xlink:href', dataUri);
    });
    
    0 讨论(0)
  • 2020-11-28 04:45

    Keeping it simple, place an svg, a canvas and an empty img into the HTML. Set all to the same size. The javascript will use the svg to create a binary large object which is then rendered in the canvas as a png image. The function call creates a clone of the canvas and converts it into a jpeg.

    function fjpg(){
     clone = c.cloneNode(true);
     ctx = clone.getContext('2d');
     ctx.fillStyle = "#FFF";
     ctx.fillRect(0, 0, clone.width, clone.height);
     ctx.drawImage(c, 0, 0);
     document.all.jp1.src=clone.toDataURL("image/jpeg");
     ctx = c.getContext('2d');
     svgBlob = new Blob( [dataPNG], { type: 'image/svg+xml' } );
     urlPNG = self.URL.createObjectURL( svgBlob );
     img = new Image();
     img.onload = function () {ctx.drawImage(img,0,0)}
     img.src = urlPNG;
    }
    c = document.all.canvas0;
    ctx = c.getContext('2d');
    data = (new XMLSerializer()).serializeToString(document.all.svg0);
    dataJPG = data.replace('>SVG<','>JPG<');
    dataPNG = data.replace('>SVG<','>PNG<');
    svgBlob = new Blob( [dataJPG], { type: 'image/svg+xml' } );
    urlJPG = self.URL.createObjectURL( svgBlob );
    img = new Image();
    img.onload = function () {
     ctx.drawImage( img, 0, 0 );
     fjpg();
    }
    img.src = urlJPG;
    <svg id='svg0' height=180 width=180><rect width=100% height=100% fill=red /><circle cx=90 cy=90 r=80 fill=green /><text x=90 y=105 font-size=60 text-anchor=middle fill=yellow>SVG</text></svg>
    <canvas id="canvas0" height=180 width=180></canvas>
    <img src='' id='jp1'>

    0 讨论(0)
  • 2020-11-28 04:47

    Here's a solution that works in IE11 as well.

    I just did a bunch of testing of various methods of this and while the above answer by Ciro Costa is fantastic in that it works in Firefox and Chrome it does not work in IE11. IE11 fails due to a security issue with rendering an svg to the canvas which requires a canvas implementation, canvg. Here's a solution using canvg that's pretty terse and works in the latest versions of Chrome, Firefox, Edge, and IE11.

    Fiddle: https://jsfiddle.net/StefanValentin/9mudw0ts/

    DOM

    <svg
      id="my-svg"
      xmlns="http://www.w3.org/2000/svg"
      xmlns:xlink="http://www.w3.org/1999/xlink"
      version="1.1"
      width="200"
      height="200"
    >
      <rect x="10" y="10" width="50" height="50" />
      <text x="0" y="100">Look, i'm cool</text>
    </svg>
    

    JavaScript

    var svg = document.querySelector('#my-svg');
    var data = (new XMLSerializer()).serializeToString(svg);
    // We can just create a canvas element inline so you don't even need one on the DOM. Cool!
    var canvas = document.createElement('canvas');
    canvg(canvas, data, {
      renderCallback: function() {
        canvas.toBlob(function(blob) {
            download('MyImageName.png', blob);
        });
      }
    });
    

    The download function above could be whatever you want to do, as there are many ways to trigger a download via JavaScript. Here's the one we use that works in all the browsers I've tested.

    // Initiate download of blob
    function download(
      filename, // string
      blob // Blob
    ) {
      if (window.navigator.msSaveOrOpenBlob) {
        window.navigator.msSaveBlob(blob, filename);
      } else {
        const elem = window.document.createElement('a');
        elem.href = window.URL.createObjectURL(blob);
        elem.download = filename;
        document.body.appendChild(elem);
        elem.click();
        document.body.removeChild(elem);
      }
    }
    
    0 讨论(0)
提交回复
热议问题