dom-to-image vs html-to-image vs html2canvas vs screenshot-desktop
Client-Side and Desktop Screenshot Generation in JavaScript
dom-to-imagehtml-to-imagehtml2canvasscreenshot-desktopSimilar Packages:

Client-Side and Desktop Screenshot Generation in JavaScript

dom-to-image, html-to-image, and html2canvas are browser-based libraries that convert DOM elements into image formats like PNG or JPEG by rendering HTML and CSS onto an HTML canvas. They enable client-side generation of visual snapshots of web content without requiring a server or headless browser. screenshot-desktop, in contrast, is a Node.js package that captures screenshots of the actual desktop or application windows using native operating system APIs—it does not render HTML and is unrelated to in-browser DOM manipulation. These tools serve fundamentally different purposes: the first three are for programmatic rendering of web content, while the last is for desktop automation and system-level screen capture.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
dom-to-image010,781-3378 years agoMIT
html-to-image07,082315 kB195a year agoMIT
html2canvas031,8253.38 MB1,048-MIT
screenshot-desktop049641.9 kB245 months agoMIT

Rendering Web Content to Images: dom-to-image vs html-to-image vs html2canvas vs screenshot-desktop

Capturing visual representations of web content is a common need — from generating social media previews to creating PDF reports or saving user-designed layouts. The four packages under review solve overlapping but distinct problems in this space. Let’s break down their technical approaches, capabilities, and trade-offs.

🖼️ Core Purpose and Rendering Strategy

dom-to-image, html-to-image, and html2canvas all convert DOM elements into raster images (PNG, JPEG, etc.) directly in the browser using JavaScript. They do not require a headless browser or external process.

screenshot-desktop, by contrast, captures screenshots of the entire desktop or specific windows — it runs only in Node.js and requires system-level access. It cannot render arbitrary HTML; it only snapshots what’s already visible on screen.

⚠️ Important: screenshot-desktop is not a web content renderer. If your goal is to turn HTML/CSS into an image programmatically (e.g., for a chart, dashboard widget, or user-generated design), screenshot-desktop is not applicable.

🧪 Browser-Based Rendering: How dom-to-image, html-to-image, and html2canvas Work

All three browser-based libraries parse the DOM, apply computed styles, and draw the result onto an HTML <canvas>. However, their implementation strategies differ significantly.

html2canvas: Pixel-Perfect Simulation via Canvas Replay

html2canvas attempts to replay the rendering process by walking the DOM tree, reading computed styles, and manually redrawing everything onto a canvas using the Canvas 2D API. It supports many CSS features (like border-radius, box-shadow, transforms) but has known limitations with complex layouts (e.g., flex, grid, clip-path).

// html2canvas: Basic usage
import html2canvas from 'html2canvas';

const element = document.getElementById('capture');
html2canvas(element).then(canvas => {
  const imgData = canvas.toDataURL('image/png');
  // Use imgData as needed
});

It offers fine-grained control via options like scale, useCORS, and logging:

html2canvas(element, {
  scale: 2,
  useCORS: true,
  logging: false
}).then(canvas => { /* ... */ });

dom-to-image: SVG Serialization + Rasterization

dom-to-image takes a different approach: it serializes the target node to an inline SVG, embedding fonts and external resources as data URLs, then draws that SVG onto a canvas. This often yields better fidelity for vector-like content (text, icons, simple shapes) but struggles with advanced CSS effects that don’t translate cleanly to SVG.

// dom-to-image: Basic usage
import domtoimage from 'dom-to-image';

const node = document.getElementById('capture');
domtoimage.toPng(node)
  .then(dataUrl => {
    // Use dataUrl
  })
  .catch(error => console.error('Error:', error));

It provides multiple output formats (toPng, toJpeg, toSvg, toCanvas) and supports filtering nodes:

const filter = (node) => !(node instanceof HTMLIFrameElement);
domtoimage.toPng(node, { filter });

🔍 Note: dom-to-image appears to be unmaintained. Its npm page shows no recent updates, and the GitHub repo (tsayen/dom-to-image) has unresolved issues and open pull requests dating back years. Use with caution in new projects.

html-to-image: A Modern Fork of dom-to-image

html-to-image is a community-maintained fork of dom-to-image that addresses many bugs and adds new features (like better font handling, improved CORS support, and TypeScript definitions). It uses the same SVG serialization strategy but with active development and better reliability.

// html-to-image: Basic usage
import { toPng } from 'html-to-image';

const node = document.getElementById('capture');
toPng(node)
  .then(dataUrl => {
    // Use dataUrl
  })
  .catch(error => console.error('Error:', error));

It also supports custom styling overrides and pixel ratio control:

const options = {
  pixelRatio: 2,
  style: { margin: '0' }
};
toPng(node, options);

💻 Desktop Screenshot: screenshot-desktop

screenshot-desktop operates entirely outside the browser context. It leverages native OS APIs (via Node.js bindings) to capture screenshots. It’s useful for automated UI testing, desktop app monitoring, or capturing full-screen content — but not for rendering dynamic HTML.

// screenshot-desktop: Capture entire screen
import screenshot from 'screenshot-desktop';

screenshot().then(imgBuffer => {
  // imgBuffer is a Buffer containing PNG data
});

// Or capture a specific window by title
screenshot({
  screen: 0,
  format: 'png',
  filename: 'output.png'
});

Key limitations:

  • Only works in Node.js environments (not in browsers).
  • Cannot render arbitrary HTML — only captures what’s already rendered by the OS.
  • Requires appropriate permissions on macOS and Linux.

📏 Feature Comparison: What Each Package Handles Well

External Resources (Images, Fonts)

  • html2canvas: Supports images via useCORS: true but may fail with cross-origin fonts unless properly configured.
  • dom-to-image: Embeds images/fonts as data URLs but often fails silently with CORS-protected assets.
  • html-to-image: Improved CORS handling; can proxy external resources through a server if needed.
  • screenshot-desktop: N/A — it captures pixels as displayed by the OS.

CSS Support

  • html2canvas: Best for basic layout and styling. Struggles with modern CSS (e.g., backdrop-filter, complex gradients).
  • dom-to-image / html-to-image: Better with text and vector graphics, but limited with CSS-only effects (shadows, blends).

Performance

  • html2canvas: Can be slow on large/complex DOM trees due to deep traversal and canvas drawing.
  • html-to-image: Generally faster than dom-to-image due to optimizations, but still blocks the main thread.
  • screenshot-desktop: Very fast (native OS call), but irrelevant for in-browser rendering.

🛠️ Real-World Decision Guide

When to use html2canvas

  • You need to capture moderately complex UIs with standard CSS.
  • You’re okay with occasional rendering inaccuracies for the sake of broad compatibility.
  • You require fine control over the rendering pipeline (e.g., custom hooks for element processing).

When to use html-to-image

  • You want better text/font rendering and are working with mostly static, vector-friendly content.
  • You need active maintenance and TypeScript support.
  • You’re capturing charts, diagrams, or user-designed cards where pixel-perfect layout isn’t critical.

When to avoid dom-to-image

  • In new projects, due to lack of maintenance. Prefer html-to-image instead.
  • If you rely on features that have been fixed only in the fork (e.g., proper z-index handling).

When to use screenshot-desktop

  • You’re building a Node.js desktop automation tool.
  • You need to capture native application windows or full-screen content.
  • Your use case is outside the browser entirely (e.g., end-to-end testing of Electron apps).

🔄 Migration Note: dom-to-image → html-to-image

If you’re currently using dom-to-image, migrating to html-to-image is straightforward:

// Before (dom-to-image)
import domtoimage from 'dom-to-image';
domtoimage.toPng(node);

// After (html-to-image)
import { toPng } from 'html-to-image';
toPng(node);

The API is nearly identical, but html-to-image exports individual functions instead of a single object.

📌 Summary Table

PackageEnvironmentRendering MethodActively Maintained?Best For
html2canvasBrowserCanvas replay✅ YesGeneral-purpose DOM capture with CSS support
html-to-imageBrowserSVG serialization✅ YesText/vector content; modern alternative
dom-to-imageBrowserSVG serialization❌ NoLegacy projects only
screenshot-desktopNode.jsOS-level screenshot✅ YesDesktop automation, not web content rendering

💡 Final Recommendation

  • For in-browser HTML-to-image conversion, choose html-to-image for most new projects — it’s reliable, maintained, and handles common cases well.
  • Fall back to html2canvas if you’re dealing with complex CSS layouts that don’t translate well to SVG.
  • Avoid dom-to-image in new codebases.
  • Use screenshot-desktop only when you genuinely need to capture desktop pixels — never for rendering HTML programmatically.

How to Choose: dom-to-image vs html-to-image vs html2canvas vs screenshot-desktop

  • dom-to-image:

    Avoid dom-to-image in new projects — it appears unmaintained, with unresolved bugs and no recent updates. If you're already using it and it works for your use case, consider migrating to html-to-image, which is a well-maintained fork with the same API but better reliability and active development.

  • html-to-image:

    Choose html-to-image when you need a modern, actively maintained library for converting DOM elements to images in the browser, especially for content heavy in text, icons, or vector graphics. It handles fonts and external resources more reliably than older alternatives and offers good TypeScript support.

  • html2canvas:

    Choose html2canvas when you're capturing moderately complex UIs that rely on standard CSS layout and styling, and you need fine-grained control over the rendering process. It’s a solid choice if your content includes effects like shadows or borders that may not serialize well to SVG.

  • screenshot-desktop:

    Choose screenshot-desktop only when you need to capture actual desktop or application window screenshots from a Node.js environment—such as in desktop automation, UI testing of native apps, or system monitoring. It cannot render arbitrary HTML and should never be used for in-browser DOM-to-image conversion.

README for dom-to-image

DOM to Image

Build Status

What is it

dom-to-image is a library which can turn arbitrary DOM node into a vector (SVG) or raster (PNG or JPEG) image, written in JavaScript. It's based on domvas by Paul Bakaus and has been completely rewritten, with some bugs fixed and some new features (like web font and image support) added.

Installation

NPM

npm install dom-to-image

Then load

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

Bower

bower install dom-to-image

Include either src/dom-to-image.js or dist/dom-to-image.min.js in your page and it will make the domtoimage variable available in the global scope.

<script src="path/to/dom-to-image.min.js" />
<script>
  domtoimage.toPng(node)
  //...
</script>

Usage

All the top level functions accept DOM node and rendering options, and return promises, which are fulfilled with corresponding data URLs.
Get a PNG image base64-encoded data URL and display right away:

var node = document.getElementById('my-node');

domtoimage.toPng(node)
    .then(function (dataUrl) {
        var img = new Image();
        img.src = dataUrl;
        document.body.appendChild(img);
    })
    .catch(function (error) {
        console.error('oops, something went wrong!', error);
    });

Get a PNG image blob and download it (using FileSaver, for example):

domtoimage.toBlob(document.getElementById('my-node'))
    .then(function (blob) {
        window.saveAs(blob, 'my-node.png');
    });

Save and download a compressed JPEG image:

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();
    });

Get an SVG data URL, but filter out all the <i> elements:

function filter (node) {
    return (node.tagName !== 'i');
}

domtoimage.toSvg(document.getElementById('my-node'), {filter: filter})
    .then(function (dataUrl) {
        /* do something */
    });

Get the raw pixel data as a Uint8Array with every 4 array elements representing the RGBA data of a pixel:

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);
          }
        }
    });

All the functions under impl are not public API and are exposed only for unit testing.


Rendering options

filter

A function taking DOM node as argument. Should return true if passed node should be included in the output (excluding node means excluding it's children as well). Not called on the root node.

bgcolor

A string value for the background color, any valid CSS color value.

height, width

Height and width in pixels to be applied to node before rendering.

style

An object whose properties to be copied to node's style before rendering. You might want to check this reference for JavaScript names of CSS properties.

quality

A number between 0 and 1 indicating image quality (e.g. 0.92 => 92%) of the JPEG image. Defaults to 1.0 (100%)

cacheBust

Set to true to append the current time as a query string to URL requests to enable cache busting. Defaults to false

imagePlaceholder

A data URL for a placeholder image that will be used when fetching an image fails. Defaults to undefined and will throw an error on failed images

Browsers

It's tested on latest Chrome and Firefox (49 and 45 respectively at the time of writing), with Chrome performing significantly better on big DOM trees, possibly due to it's more performant SVG support, and the fact that it supports CSSStyleDeclaration.cssText property.

Internet Explorer is not (and will not be) supported, as it does not support SVG <foreignObject> tag

Safari is not supported, as it uses a stricter security model on <foreignObject> tag. Suggested workaround is to use toSvg and render on the server.`

Dependencies

Source

Only standard lib is currently used, but make sure your browser supports:

Tests

Most importantly, tests depend on:

  • js-imagediff, to compare rendered and control images

  • ocrad.js, for the parts when you can't compare images (due to the browser rendering differences) and just have to test whether the text is rendered

How it works

There might some day exist (or maybe already exists?) a simple and standard way of exporting parts of the HTML to image (and then this script can only serve as an evidence of all the hoops I had to jump through in order to get such obvious thing done) but I haven't found one so far.

This library uses a feature of SVG that allows having arbitrary HTML content inside of the <foreignObject> tag. So, in order to render that DOM node for you, following steps are taken:

  1. Clone the original DOM node recursively

  2. Compute the style for the node and each sub-node and copy it to corresponding clone

    • and don't forget to recreate pseudo-elements, as they are not cloned in any way, of course
  3. Embed web fonts

    • find all the @font-face declarations that might represent web fonts

    • parse file URLs, download corresponding files

    • base64-encode and inline content as data: URLs

    • concatenate all the processed CSS rules and put them into one <style> element, then attach it to the clone

  4. Embed images

    • embed image URLs in <img> elements

    • inline images used in background CSS property, in a fashion similar to fonts

  5. Serialize the cloned node to XML

  6. Wrap XML into the <foreignObject> tag, then into the SVG, then make it a data URL

  7. Optionally, to get PNG content or raw pixel data as a Uint8Array, create an Image element with the SVG as a source, and render it on an off-screen canvas, that you have also created, then read the content from the canvas

  8. Done!

Things to watch out for

  • if the DOM node you want to render includes a <canvas> element with something drawn on it, it should be handled fine, unless the canvas is tainted - in this case rendering will rather not succeed.

  • at the time of writing, Firefox has a problem with some external stylesheets (see issue #13). In such case, the error will be caught and logged.

Authors

Anatolii Saienko, Paul Bakaus (original idea)

License

MIT