DOM to Image

Dom-to-image is a JS library that converts any DOM node into a vector (SVG) or raster (PNG or JPEG) image.

The installation

npm install dom-to-image -S
Copy the code

loading

/* in ES 6 */
import domtoimage from 'dom-to-image';
/* in ES 5 */
var domtoimage = require('dom-to-image');
Copy the code

usage

All higher-order functions accept DOM nodes and render options and return promises.

  1. Retrieve the Base64 encoded DATA URL of a PNG image:
<div id="my-node"></div>
Copy the code
var node = document.getElementById('my-node');
// Options is optional
var options = {}  
domtoimage.toPng(node, options)
    .then(function (dataUrl) {
        var img = new Image();
        img.src = dataUrl;
        document.body.appendChild(img);
    })
    .catch(function (error) {
        console.error('oops, something went wrong! ', error);
    });
Copy the code
  1. Get image blob:
domtoimage.toBlob(document.getElementById('my-node'))
    .then(function (blob) { 
        console.log('blob', blob)
    });
Copy the code
  1. Get the Base64 encoded DATA URL of a JPEG image and download it:
domtoimage.toJpeg(document.getElementById('my-node'), { quality: 0.95 })
    .then(function (dataUrl) {
        var link = document.createElement('a');
        link.download = 'my-image-name.jpeg';
        link.href = dataUrl;
        link.click();
});
Copy the code
  1. Get the SVGdata URL, but filter out all elements:
function filter (node) {
    return(node.tagName ! = ='i');
}
 
domtoimage.toSvg(document.getElementById('my-node'), {filter: filter})
    .then(function (dataUrl) {
        /* do something */
});
Copy the code
  1. Get the raw pixel data in the form of uint8 arrays with 4 array elements representing one pixel RGBA data:
var node = document.getElementById('my-node');
 
domtoimage.toPixelData(node)
    .then(function (pixels) {
        for (var y = 0; y < node.scrollHeight; ++y) {
          for (var x = 0; x < node.scrollWidth; ++x) {
            pixelAtXYOffset = (4 * y * node.scrollHeight) + (4 * x);
            /* pixelAtXY is a Uint8Array[4] containing RGBA values of the pixel at (x, y) in the range 0.. 255 * /
            pixelAtXY = pixels.slice(pixelAtXYOffset, pixelAtXYOffset + 4); }}});Copy the code

The options parameter

Name type Default Description
filter Function A function that takes a DOM node as an argument. Return true if the passed node should be included in the output (excluding nodes means excluding children as well)
bgcolor String Background color string value, any valid CSS color value.
height Number The height (in pixels) applied to the node before rendering.
width Number The width (in pixels) applied to the node before rendering.
style Object Object, whose properties are copied into the node’s style before rendering.
quality Number 1.0 A number between 0 and 1 indicates the image quality of a JPEG image (e.g. 0.92=>92%). Default is 1.0 (100%)
cacheBust Boolean false Set to true to append the current time as a query string to the URL request to enable clear caching.
imagePlaceholder Boolean undefined The data URL of the image is used as a placeholder when the image fails to be obtained. Defaults to undefined and will raise an error on failed images.

The principle of

Dom-to-image uses a feature of SVG that allows arbitrary HTML content to be included in tags.

  • Recursively clone the original DOM node

  • Compute the style of the node and each child node and copy it to the appropriate clone

    • Create pseudo elements because they are not cloned in any way
  • Embedding web fonts

    • Find all the @font face declared Web fonts
    • Parse the file URL and download the corresponding file
    • Base64 encoded inline as Data: URLs
    • Put all the processed CSS into it and then attach it to the clone
  • The embedded image

    • inEmbed image URL
    • usebackgroundCSS properties, similar to fonts
  • Serialize the cloned node to XML

  • Wrap the XML in the tag, then wrap it in THE SVG, and then make it a Data URL

  • Alternatively, to get the PNG content or raw pixel data in the form of Uint8Array, you can create an SVG-sourced image element and render it on the canvas you have created and read the content from the canvas

Partial source code analysis

dom-to-image.js

// Default impl options var defaultOptions = { // Default is to fail on error, no placeholder imagePlaceholder: undefined, // Default cache bust is false, it will use the cache cacheBust: false }; var domtoimage = { toSvg: toSvg, toPng: toPng, toJpeg: toJpeg, toBlob: toBlob, toPixelData: toPixelData, impl: { fontFaces: fontFaces, images: images, util: util, inliner: inliner, options: {} } }; if (typeof module ! == 'undefined') module.exports = domtoimage; else global.domtoimage = domtoimage;Copy the code
  • DefaultOptions sets defaultOptions
  • Domtoimage core API:
    • toSvg

    • toPng

    • toJpeg

    • toBlob

    • toPixelData

  • Example: toJpeg: Canvas instance returned by draw, using canvas’s toDataURL method to generate a JPEG image. The toSvg function recursively clones the original DOM node, serializes the cloned node to XML, wraps the XML into a tag, wraps it into SVG, and converts it to a dataURL.
function toJpeg(node, options) { options = options || {}; Return the draw (node, the options). Then (function (canvas) {return canvas. ToDataURL (' image/jpeg, the options. Quality | | 1.0); }); }Copy the code
function draw(domNode, options) { return toSvg(domNode, options) .then(util.makeImage) .then(util.delay(100)) .then(function (image) { var canvas = newCanvas(domNode); canvas.getContext('2d').drawImage(image, 0, 0); return canvas; }); function newCanvas(domNode) { var canvas = document.createElement('canvas'); canvas.width = options.width || util.width(domNode); canvas.height = options.height || util.height(domNode); if (options.bgcolor) { var ctx = canvas.getContext('2d'); ctx.fillStyle = options.bgcolor; ctx.fillRect(0, 0, canvas.width, canvas.height); } return canvas; }}Copy the code
function toSvg(node, options) { options = options || {}; copyOptions(options); return Promise.resolve(node) .then(function (node) { return cloneNode(node, options.filter, true); }) .then(embedFonts) .then(inlineImages) .then(applyOptions) .then(function (clone) { return makeSvgDataUri(clone, options.width || util.width(node), options.height || util.height(node) ); }); function applyOptions(clone) { if (options.bgcolor) clone.style.backgroundColor = options.bgcolor; if (options.width) clone.style.width = options.width + 'px'; if (options.height) clone.style.height = options.height + 'px'; if (options.style) Object.keys(options.style).forEach(function (property) { clone.style[property] = options.style[property]; }); return clone; }}Copy the code

Dom-to-image – Github address

Dom-to-image-npm Address