1

I'm using a plugin (dom-to-image) to generate a SVG content from a div. It returns me a dataURL like this:

data image/xml, charset utf-8, <svg...

If a put this on a <img src the image is shown to normally.

The intent is to grab this dataURL, convert it to base64 so I can save it as an image.png on a mobile app.

Is it possible?

I tryied this solution https://stackoverflow.com/a/28450879/1691609 But coudn't get to work. The console fire an error about the dataUrl

TypeError: Failed to execute 'serializeToString' on 'XMLSerializer': parameter 1 is not of type 'Node'.

==== UPDATE :: PROBLEM EXPLANATION/HISTORY ====

I'm using Ionic Framework, so my project is an mobile app. The dom-to-image is already working cause right now, its rendering a PNG through toPng function. The problem is the raster PNG is a blurry.

So I thought: Maybe the SVG will have better quality. And it IS!! Its 100% perfect, actually.

On Ionic, I'm using 2 step procedure to save the image. After get the PNG generated by the dom-to-img(base64) dataURL, I convert it to a Blob and then save into device. This is working, but the final result, as I said, is blurry.

Then with SVG maybe it will be more "high quality" per say.

So, in order to do "minimal" change on a process that s already working :D I just need to convert an SVG into base64 dataURL....

Or, as some of you explained to me, into something else, like canvas... I don't know any much :/

===

Sorry for the long post, and I really, really thank your help guys!!

Community
  • 1
  • 1
Rafael de Castro
  • 888
  • 4
  • 16
  • 37
  • 1
    You want a png version of your svg ? Then you need to rasterize it. The only way from js is through the canvas API. You could directly draw your image with `drawImage` method, but this won't work in IE browsers. You could also try a library like canvg, but then you would need to first parse the dataURL (do the inverse of the Q/A you pointed to). base64 is just a string encoding, it has nothing to do with the format of your image. – Kaiido Nov 09 '16 at 14:56
  • 3
    Why would you need to convert it to base64 in order to save it as an image png? If you want us to determine why you're getting a TypeError we'll need a [mcve]. – Robert Longson Nov 09 '16 at 15:05
  • @Kaiido I updated my question with an explanation :D – Rafael de Castro Nov 09 '16 at 17:05
  • @RobertLongson I updated my question with an explanation :D – Rafael de Castro Nov 09 '16 at 17:05
  • 1
    Oh I missed you want to convert HTML to png. If you plan to support ios or IE, don't do this. http://stackoverflow.com/questions/40434037/generate-svg-without-foreignobject-tag And actually even for other browsers you'll be highly limitated. – Kaiido Nov 09 '16 at 23:01
  • @Kaiido thx :) Luckly I won't have :D On my app I'm using the Crosswalk feature, that imbue a "Chrome browser" on the app. So every device will run in the same way... – Rafael de Castro Nov 09 '16 at 23:19
  • But still even chrome has severe limitations with this hack. You'd be better using a native screenshot (I don't know what APIs ionic has access to), or at least a library like html2canvas ehich redraw your elements using canvas API. – Kaiido Nov 09 '16 at 23:34
  • @Kaiido html2canvas was my first choice. But my render content has a div with css border-radius to appear like a mirror. The plugin simply forget that and don't render properly. Dom-to-img did the job with no question, but the image got blurry :( – Rafael de Castro Nov 10 '16 at 00:19

2 Answers2

9

EDIT COUPLE OF YARS LATER

  • Use JS fiddle for a working example: https://jsfiddle.net/msb42ojx/
  • Note, if you don't own DOM content (images), and those images don't have CORS enabled for everyone (Access-Control-Allow-Origin header), canvas cant render those images

I'm not trying to find out why is your case not working, here is how I did when I had something similar to do:

  • get the image sourcce (dom-to-image result)
  • set up a canvas with that image inside (using the image source)
  • download the image from canvas in whatever image you like: png, jpeg whatever

by the way you can resize the image to a standard format

document.getElementById('mydownload').onclick= function(){
  var wrapper = document.getElementById('wrapper');
  //dom to image
  domtoimage.toSvg(wrapper).then(function (svgDataUrl) {
  //download function    
  downloadPNGFromAnyImageSrc(svgDataUrl);
  });
}
function downloadPNGFromAnyImageSrc(src)
{
  //recreate the image with src recieved
  var img = new Image;
  //when image loaded (to know width and height)
  img.onload = function(){
    //drow image inside a canvas
    var canvas = convertImageToCanvas(img);
    //get image/png from convas
    var pngImage =  convertCanvasToImage(canvas);
    //download
    var anchor = document.createElement('a');
    anchor.setAttribute('href', pngImage.src);
    anchor.setAttribute('download', 'image.png');
    anchor.click();
  };
  
  img.src = src;


    // Converts image to canvas; returns new canvas element
  function convertImageToCanvas(image) {
        var canvas = document.createElement("canvas");
        canvas.width = image.width;
        canvas.height = image.height;
        canvas.getContext("2d").drawImage(image, 0, 0);
        return canvas;
    }
    
    
    // Converts canvas to an image
    function convertCanvasToImage(canvas) {
        var image = new Image();
        image.src = canvas.toDataURL("image/png");
        return image;
    }
}
#wrapper{
  background: red;
  color: blue;
}
<script src="https://rawgit.com/tsayen/dom-to-image/master/src/dom-to-image.js"></script>
<button id='mydownload'>Download DomToImage</button>
<div id="wrapper">
  <img src="http://i.imgur.com/6GvKdxY.jpg"/>
  <div> DUDE IS WORKING</div>
  <img src="http://i.imgur.com/6GvKdxY.jpg"/>
</div>
SilentTremor
  • 4,747
  • 2
  • 21
  • 34
  • Got it, try to see if this implementation brake the downloaded image, it should't, as I said in answer every time I used canvas to process images on client side, but is your choice how you do it. – SilentTremor Nov 10 '16 at 07:48
2

I translated @SilentTremor's solution into React/JS-Class:

class SVGToPNG {
  static convert = function (src) {
    var img = new Image();

    img.onload = function () {
      var canvas = SVGToPNG.#convertImageToCanvas(img);
      var pngImage = SVGToPNG.#convertCanvasToImage(canvas);

      var anchor = document.createElement("a");
      anchor.setAttribute("href", pngImage.src);
      anchor.setAttribute("download", "image.png");
      anchor.click();
    };

    img.src = src;
  };

  static #convertImageToCanvas = function (image) {
    var canvas = document.createElement("canvas");
    canvas.width = image.width;
    canvas.height = image.height;
    canvas.getContext("2d").drawImage(image, 0, 0);
    return canvas;
  };

  static #convertCanvasToImage = function (canvas) {
    var image = new Image();
    image.src = canvas.toDataURL("image/png");
    return image;
  };
}

export default SVGToPNG;

Usage:

let dataUrl = someCanvas.toDataURL("image/svg+xml");
SVGToPNG.convert(dataUrl);
Sebastian
  • 1,593
  • 4
  • 26
  • 41