dom-to-image、html-to-image、html2canvas は、ブラウザ上で DOM 要素を画像(PNG/JPEG/SVG)に変換するためのライブラリです。これらは主に、UI のスクリーンショット取得、レポート生成、SNS シェア用画像作成などのフロントエンドユースケースで使われます。一方、screenshot-desktop は Node.js 向けのデスクトップ全体のスクリーンショット取得ライブラリであり、ブラウザ環境ではなく Electron やデスクトップ自動化ツールなどで使用されます。この比較では、Web フロントエンド開発者が DOM キャプチャ機能を実装する際に適切なパッケージを選定できるよう、技術的特性と実用性に焦点を当てて解説します。
フロントエンド開発において、DOM 要素を画像として保存・共有する必要が生じることはよくあります。例えば、レポート出力、SNS シェア用プレビュー、または UI の視覚的バグ報告などが該当します。しかし、これらの要望を実現するには複数の技術的制約(CORS、フォント、SVG、iframe など)を乗り越える必要があります。この記事では、代表的な npm パッケージである dom-to-image、html-to-image、html2canvas、および screenshot-desktop を、実際の開発現場での使用観点から深く比較します。
まず重要なのは、各パッケージが「何をキャプチャできるか」です。
dom-to-image、html-to-image、html2canvas はすべて ブラウザ上で動作し、DOM 要素を画像化することを目的としています。これらはクライアントサイド JavaScript で使われ、ユーザーの画面内の特定の HTML 要素(例: <div id="chart">)を PNG や JPEG に変換します。
一方、screenshot-desktop は Node.js 向けのデスクトップ全体またはディスプレイのスクリーンショット取得ライブラリです。これはブラウザ外で動作し、Electron アプリやデスクトップ自動化ツールなどで使われます。Web ページ内の要素を撮影する用途にはまったく使えません。
💡 補足:
screenshot-desktopはブラウザ環境で動作しないため、通常の Web アプリ(React/Vue/Angular など)では使用できません。誤ってインストールしないよう注意が必要です。
以下では、Web フロントエンド向けの3つのライブラリ(dom-to-image、html-to-image、html2canvas)を中心に比較します。
html2canvashtml2canvas は、Canvas API を使って DOM を再現します。CSS プロパティを解析し、それを Canvas コンテキストに変換して描画します。この方式の利点は、iframe や外部ドメインの画像などの制限が比較的少ないことです(ただし CORS 制約は依然存在)。
ただし、完全な CSS サポートがあるわけではなく、一部のプロパティ(例: filter、clip-path、transform-style: preserve-3d)は正しく描画されないことがあります。
// html2canvas の基本的な使い方
import html2canvas from 'html2canvas';
const element = document.getElementById('capture');
html2canvas(element).then(canvas => {
const imgData = canvas.toDataURL('image/png');
// imgData をダウンロードまたは表示
});
dom-to-image と html-to-image両者は非常に似ていますが、html-to-image は dom-to-image のフォークであり、メンテナンスが活発です。動作原理は共通で、以下のステップで画像を生成します:
<foreignObject> として埋め込む<img> 要素で読み込み、Canvas に描画この方式は CSS の忠実度が高い(特にフォントや装飾)ですが、CORS 制約が厳しくなります。外部ドメインの画像やフォントはブロックされる可能性があります。
// dom-to-image の使い方
import domtoimage from 'dom-to-image';
const node = document.getElementById('capture');
domtoimage.toPng(node)
.then(dataUrl => {
// dataUrl を使用
});
// html-to-image の使い方(API はほぼ同じ)
import { toPng } from 'html-to-image';
const node = document.getElementById('capture');
toPng(node)
.then(dataUrl => {
// dataUrl を使用
});
⚠️ 注意:
dom-to-imageは GitHub リポジトリが更新されておらず、npm にも「このパッケージは非推奨です。代わりにhtml-to-imageを使ってください」という警告が記載されています。新規プロジェクトでは使用すべきではありません。
html2canvasuseCORS: true オプション必須)allowTaint: true と useCORS: true を組み合わせて、ある程度対応可能html2canvas(element, {
useCORS: true,
allowTaint: true
}).then(canvas => { /* ... */ });
html-to-imagefontEmbedCssUrl オプションで CSS を埋め込むことで対応可能import { toPng } from 'html-to-image';
toPng(node, {
fontEmbedCssUrl: '/path/to/fonts.css'
}).then(dataUrl => { /* ... */ });
dom-to-image にも同様のオプションがありますが、メンテナンスされていないため、最新のブラウザ挙動に対応していない可能性があります。
| 機能 | html2canvas | html-to-image | dom-to-image |
|---|---|---|---|
| 解像度スケーリング | ✅ (scale オプション) | ✅ (pixelRatio) | ✅ (pixelRatio) |
| 背景指定 | ✅ (backgroundColor) | ✅ (backgroundColor) | ✅ (bgcolor) |
| 要素の除外 | ✅ (ignoreElements) | ✅ (skipNode) | ✅ (filter) |
| SVG サポート | ⚠️ 限定的 | ✅ 良好 | ✅ 良好 |
| ダウンロードヘルパー | ❌ | ✅ (download 関数) | ❌ |
html-to-image は download ユーティリティ関数を提供しており、画像を直接ダウンロードさせるのが簡単です:
import { toPng, download } from 'html-to-image';
toPng(node).then(download);
一方、html2canvas は純粋に Canvas を返すだけなので、ダウンロード処理は自分で実装する必要があります。
screenshot-desktop は Node.js 環境専用であり、以下のような用途に使われます:
// screenshot-desktop の使い方(Node.js のみ)
const screenshot = require('screenshot-desktop');
screenshot().then(img => {
// img は Buffer(PNG データ)
require('fs').writeFileSync('screenshot.png', img);
});
このライブラリは ブラウザで動作しないため、Web アプリの DOM キャプチャには一切使えません。混同しないよう注意してください。
html-to-imagehtml2canvasscreenshot-desktophtml-to-image への移行を検討公式 npm ページおよび GitHub リポジトリの情報によると:
dom-to-image は非推奨(deprecated) と明記されています。最後のコミットは数年前であり、バグ修正や新機能追加は行われていません。代わりに、作者が推奨している html-to-image を使用してください。これは dom-to-image の後継として開発されており、API 互換性を保ちつつ、バグ修正と改善が継続されています。
| パッケージ | 推奨度 | 主な用途 | 注意点 |
|---|---|---|---|
html-to-image | ⭐⭐⭐⭐⭐ | Web フロントエンドでの高品質 DOM キャプチャ | CORS 制約に注意 |
html2canvas | ⭐⭐⭐⭐☆ | 外部リソースを含む DOM キャプチャ | CSS 再現性に若干の限界 |
dom-to-image | ⚠️ 非推奨 | (新規使用不可) | 使用を避けてください |
screenshot-desktop | ⭐⭐⭐⭐☆(ただし用途限定) | Node.js デスクトップアプリでのスクリーンショット | ブラウザでは動作しない |
結論として:
html-to-image を試す。html2canvas を検討する。dom-to-image は新規プロジェクトで使うべきではない。screenshot-desktop を使うが、Web フロントエンドとは無関係であることを理解しておくこと。これらの選択は、単なる「どちらが人気か」ではなく、「あなたのアプリの技術的制約と要件にどれが最もフィットするか」に基づいて判断すべきです。
dom-to-image は非推奨(deprecated)と公式に明記されており、新規プロジェクトでの使用は避けるべきです。GitHub リポジトリの更新も長期間停止しており、バグ修正や新機能追加は行われていません。既存コードで使用されている場合は、後継の html-to-image への移行を強く推奨します。
html-to-image は dom-to-image のメンテナンスされたフォークであり、高忠実度の DOM キャプチャが必要な Web フロントエンドプロジェクトに最適です。CSS 装飾や Web フォントの再現性が高く、ダウンロードヘルパー関数も提供されています。ただし、CORS 制約が厳しく、外部ドメインの画像やフォントを使用する場合は事前に対策が必要です。
html2canvas は、外部リソース(CORS 許可済みの画像や iframe)を含む複雑な DOM をキャプチャする必要がある場合に適しています。Canvas ベースの描画方式により、一部の CSS プロパティの再現性に限界がありますが、柔軟なオプション設定と広いブラウザサポートが強みです。描画品質より可用性を重視するケースに向いています。
screenshot-desktop は Node.js 環境専用のデスクトップスクリーンショットライブラリであり、ブラウザベースの Web アプリでは使用できません。Electron アプリやデスクトップ自動化ツールで、OS レベルの全画面または特定ディスプレイのキャプチャが必要な場合にのみ選択してください。DOM 要素の画像化とは無関係です。
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.
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 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>
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.
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.
A string value for the background color, any valid CSS color value.
Height and width in pixels to be applied to node before rendering.
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.
A number between 0 and 1 indicating image quality (e.g. 0.92 => 92%) of the JPEG image. Defaults to 1.0 (100%)
Set to true to append the current time as a query string to URL requests to enable cache busting. Defaults to false
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
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.`
Only standard lib is currently used, but make sure your browser supports:
<foreignObject> tagMost 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
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:
Clone the original DOM node recursively
Compute the style for the node and each sub-node and copy it to corresponding clone
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
Embed images
embed image URLs in <img> elements
inline images used in background CSS property, in a fashion similar to
fonts
Serialize the cloned node to XML
Wrap XML into the <foreignObject> tag, then into the SVG, then make it a
data URL
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
Done!
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.
Anatolii Saienko, Paul Bakaus (original idea)
MIT