0

I'm looking for library or code snippet which will help me to convert HTML DOM node element to image/png file.

I tried to use html2canvas library but it does not render svg nodes, and in my current project i have a lot of them. Also i tried to use canvg library to convert all SVG elements on page to Canvas elements, but canvg always threw error on render step:

Uncaught (in promise) TypeError: Cannot read property 'ImageClass' of undefined

Code snippet that is used to conver SVGs to Canvas:

export const svgToCanvas = () => {
  const print = document.getElementsByClassName('print-page')[0]
  const svgElements = print.getElementsByTagName('svg')
  _.each(svgElements, e => {
    let xml
    const canvas = document.createElement('canvas')
    canvas.className = 'screenShotTempCanvas'
    xml = (new window.XMLSerializer()).serializeToString(e)
    xml = xml.replace(/xmlns=http:\/\/www\.w3\.org\/2000\/svg/, '')
    canvg(canvas, xml)
    e.parentNode.insertBefore(canvas, e.nextSibling)
    e.classList.add('tempHide')
    e.style.display = 'none'
  })

  const temps = document.getElementsByClassName('.screenShotTempCanvas')
  _.each(temps, e => {
    e.remove()
  })
  const svgs = document.getElementsByClassName('tempHide')
  _.each(svgs, e => {
    if (e) {
      e.style.display = 'block'
      e.classList.remove('tempHide')
    }
  })
}

Error throws on this line in canvg code:

if (nodeEnv) {
    if (!s || s === '') {
        return;
    }
    ImageClass = opts['ImageClass'];  //<= error throws here
    CanvasClass = target.constructor;
    svg.loadXml(target.getContext('2d'), s);
    return;
}

I also tried to convert node to PDF format using jsPDF and html-pdf libraries, but in this case all styles are disappeared from node, and i need them not to be lost.

Can anyone provide me with appropriate approach how to convert HTML DOM node (which is rich on SVG elements) to image ?

M Reza
  • 18,350
  • 14
  • 66
  • 71
Vlad Morzhanov
  • 1,260
  • 3
  • 14
  • 29

1 Answers1

2

This seems to be the result of seriously bad testing and documenting by canvg authors. The line the error is thrown at was introduced as part of a pull request that supposedly added support for executing canvg in a node environment. But it seems it was only tested to work if it was used as a dependency in node-svg2img.

If you look at that source, you will find the following (excerpt):

var canvg = require('canvg'),
    Canvas = require('canvas');

function convert(svgContent) {
    var canvas = new Canvas();
    canvg(canvas, svgContent, { ignoreMouse: true, ignoreAnimation: true, ImageClass: Canvas.Image });
    return canvas;
}

As you can see, canvg is called with an option ImageClass that has never been documented, and whose content is dependent on a module canvas that is never stated as a dependency for canvg. (And that is not a lightweight one, it is the complete <canvas> implementation.)

Now you never stated that you were doing all this in node, but I will assume you do, otherwise I would not understand why the line causing the error got called at all.

It seems a successfull call to document.createElement('canvas') does not indicate you have the canvas module installed. This note in the jsdom doc tells you what needs to be done.

From there, calling canvg in your code with

import Image from 'canvas';

canvg(canvas, xml, {ImageClass: Image});

should get you runing.

ccprog
  • 20,308
  • 4
  • 27
  • 44
  • Thanks for answer, it really useful. `canvg` library works now without any errors. But it does not works well and transforms svg elements into canvas with distortions. Can you suggest any other library to tansform svg to canvas, or another approach to export node element as image ? – Vlad Morzhanov May 16 '18 at 07:10
  • I don't know if there is another library, but if you use [PhantomJS](https://www.npmjs.com/package/phantom) , you'll have a complete headless browser where you can run the native canvas API without the need for canvg. – ccprog May 16 '18 at 14:12