John
John

Reputation: 495

object HTMLImageElement cannot be "saved as" image in Internet Explorer

I try to: create an SVG element with D3, click a button to convert it to an image using CANVAS, so it could be right clicked and "saved as" image.

The problem: the [object HTMLImageElement] object is not visible by Internet Explorer as "image" so when I right click on it, it doesn't prompt the "Save image as..." option. In Chrome and Firefox it works ok.

I have the following HTML code:

<input type="button" id="toPngBtn" value="Save" /><br />
<div id="myDiv"></div>
<div id="exportDiv"></div>

And the following javascript code:

    //Make an SVG Container
    var svgContainer = d3.select("#myDiv").append("svg")
        .attr("id", "myCircle")
        .attr("width", 60)
        .attr("height", 60);

     //Draw the Circle
     var circle = svgContainer.append("circle")
        .attr("cx", 30)
        .attr("cy", 30)
        .attr("r", 20);

    // Save button to 
     d3.select("#toPngBtn").on("click", function () {
        var svg = document.getElementById('myCircle');
        var xml = new XMLSerializer().serializeToString(svg);
        var data = "data:image/svg+xml;base64," + btoa(xml);
        var image = new Image;
        image.src = data;
        var imgWidth = image.width;
        var imgHeigth = image.height;
        var exportDiv = document.getElementById('exportDiv');
        exportDiv.innerHTML = '<canvas id="exportCanvas" width="' + imgWidth + '" height="' + imgHeigth + '"></canvas>';

        var canvas = document.querySelector("canvas"),
            context = canvas.getContext("2d");

         canvas.innerHTML = image;

        image.onload = function () {
            context.drawImage(image, 0, 0);
        };
    });

So what I do is the following: When the page loads I draw a circle using D3.js. If the "toPngBtn" button is clicked, then I will get the svg element, serialize it, create a new Image() object and append the blob to the source. I get the dimensions of the SVG and create a new CANVAS of the same size and append it to a div. I set the innerHTML of the canvas to be the newly created image and when the image is loaded, I tell the context to draw the image.

The good part is that the image appears on the page. The bad part is that in Internet Explorer I cannot right click on the image and save it. Works fine in Chrome and Firefox.

The question: Is there a workaround for that? I tried to use the

...    
image.onload = function () {
                context.drawImage(image, 0, 0);
                var a = document.createElement("a");
                a.download = "svg-graph.png";
                a.href = canvas.toDataURL("image/png");
                a.click();
            };
...

to prompt the file for download, but again Internet Explorer doesn't allow CORS so it doesn't work... Any ideas on how to make an image from SVG downloadable in IE? Thank you.

Upvotes: 0

Views: 1925

Answers (2)

Kaiido
Kaiido

Reputation: 136965

Drawing an svg image onto a canvas did taint the canvas in IE < Edge ( and in latest Safari if a <foreignObject> is in the svg being drawn), for security reasons.

Hence, when you right click the drawn canvas, you can't anymore access the save image as... functionality.

However, in these browsers, you can just right click the original svg element and choose save image as... => yourFile.png.

So the solution is either to first try to render the svg on the canvas, then check if it was tainted by calling its toDataURL() method in a try-catch block, or to do some UA-string spoofing and directly send some notice to the user to right click the image and do it by himself...

Note that even if the canvas is tainted, it has nothing to do with cross-origin-resources in your case.

Upvotes: 3

Gilsha
Gilsha

Reputation: 14589

Internet Explorer does not support download attribute on anchor tags. So for Internet Explorer, you can try the following code

window.navigator.msSaveBlob(canvas.msToBlob(), "svg-graph.png");

Completed code:

function isIE() {
  var userAgent = window.navigator.userAgent;
  return userAgent.indexOf("MSIE ") > -1 || userAgent.indexOf("Trident/") > -1;
}
image.onload = function () {
   context.drawImage(image, 0, 0);
   if(isIE()){ 
      window.navigator.msSaveBlob(canvas.msToBlob(), "svg-graph.png");
   } else{
      var a = document.createElement("a");
      a.download = "svg-graph.png";
      a.href = canvas.toDataURL("image/png");
      a.click();
   }
};

Upvotes: 1

Related Questions