dom-to-image vs html-to-image vs html2canvas
HTML要素を画像に変換するライブラリの比較
dom-to-imagehtml-to-imagehtml2canvas類似パッケージ:

HTML要素を画像に変換するライブラリの比較

dom-to-imagehtml-to-imagehtml2canvas はいずれもブラウザ上でHTML要素を画像(PNGやJPEGなど)に変換するためのJavaScriptライブラリです。これらはスクリーンショット機能、レポート生成、コンテンツ共有などのユースケースで広く使われます。dom-to-imagehtml-to-image はSVGベースのアプローチを採用し、CSSスタイルやフォントをより正確に再現します。一方、html2canvas はCanvas APIを直接利用して描画をシミュレートし、複雑なDOM構造にも対応しますが、一部のCSSプロパティや外部リソースの処理に制限があります。

npmのダウンロードトレンド

3 年

GitHub Starsランキング

統計詳細

パッケージ
ダウンロード数
Stars
サイズ
Issues
公開日時
ライセンス
dom-to-image010,776-3399年前MIT
html-to-image07,158315 kB1971年前MIT
html2canvas031,8653.38 MB1,052-MIT

HTML要素を画像に変換するライブラリ:dom-to-image vs html-to-image vs html2canvas

フロントエンド開発で「画面の一部を画像として保存したい」という要件はよくあります。例えば、グラフの共有、レポート出力、ユーザー生成コンテンツのプレビューなどです。そのようなニーズを満たす代表的なnpmパッケージが dom-to-imagehtml-to-imagehtml2canvas です。これらは似た目的を持ちますが、内部実装、対応範囲、メンテナンス状況に大きな違いがあります。この記事では、実際のコード例を交えながら、各ライブラリの特性と選定基準を解説します。

⚠️ メンテナンス状況:非推奨かどうかが重要

まず最初に確認すべきは、パッケージが現在もアクティブにメンテナンスされているかです。

  • dom-to-imagenpmページ および GitHubリポジトリ で明確に 非推奨(deprecated) とされています。作者は後継として html-to-image を推奨しています。新規プロジェクトでの使用は避けてください。

  • html-to-imagedom-to-image のフォークであり、GitHubリポジトリ は活発に更新されており、TypeScript定義やモダンなツールチェーンをサポートしています。

  • html2canvas は長年利用されてきた成熟したライブラリで、公式サイト も整備されており、定期的に更新されています。

💡 新規プロジェクトでは、dom-to-image は選択肢から外しましょう。

🖼️ 基本的な使い方:10行で画像生成

各ライブラリの基本的な使い方を比較します。対象は <div id="capture">Hello World</div> という要素とします。

dom-to-image(非推奨)

import domtoimage from 'dom-to-image';

const node = document.getElementById('capture');
domtoimage.toPng(node)
  .then(dataUrl => {
    const img = new Image();
    img.src = dataUrl;
    document.body.appendChild(img);
  });

html-to-image

import { toPng } from 'html-to-image';

const node = document.getElementById('capture');
toPng(node)
  .then(dataUrl => {
    const img = new Image();
    img.src = dataUrl;
    document.body.appendChild(img);
  });

html2canvas

import html2canvas from 'html2canvas';

const node = document.getElementById('capture');
html2canvas(node).then(canvas => {
  const img = new Image();
  img.src = canvas.toDataURL();
  document.body.appendChild(img);
});

見た目は似ていますが、内部の処理は大きく異なります。

🔧 内部実装:SVG vs Canvas

dom-to-image / html-to-image:SVG経由の描画

これらのライブラリは、DOM要素を一時的にSVGに変換し、そのSVGをCanvasに描画して画像データURLを生成します。この方式の利点は、CSSスタイルやWebフォントを比較的正確に再現できることです。

// html-to-image の内部処理イメージ
// 1. DOM → SVG文字列(インラインスタイル付き)
// 2. SVGをBlob URLに変換
// 3. そのURLをImage要素で読み込み
// 4. Canvasに描画 → toDataURL()

ただし、iframe、動的Canvas、video要素などはサポートされません。また、CORSで保護された外部画像は描画されない可能性があります。

html2canvas:CanvasによるDOM再現

html2canvas はブラウザのレンダリングエンジンを模倣し、Canvas APIを使ってDOMノードを1つずつ描画します。つまり、実際のスクリーンショットではなく「再現」 です。

この方式の利点は、iframe以外のほとんどのHTML要素を扱えることです。ただし、以下の制限があります:

  • box-shadowtransformfilter などの一部CSSプロパティが正しく描画されない
  • 外部ドメインの画像やフォントはCORS設定がないと表示されない
  • 動的なCanvasやWebGLコンテンツはキャプチャ不可

🎨 スタイルとフォントの再現性

Webフォントの扱い

html-to-image は、fontEmbedCss オプションでGoogle FontsなどのWebフォントを自動埋め込みます。

import { toPng } from 'html-to-image';

toPng(node, {
  fontEmbedCss: true // デフォルトで有効
});

一方、html2canvasuseCORS: true オプションを指定することで、CORSヘッダー付きのフォント/画像を読み込もうとしますが、サーバー側の設定が必須です。

html2canvas(node, {
  useCORS: true
});

複雑なCSS(例:clip-path

clip-pathmask といった高度なCSSプロパティは、html-to-image ではSVG互換のもののみ動作し、html2canvas では未対応です。どちらも完全な再現は難しいため、事前に検証が必要です。

📦 オプションとカスタマイズ性

画像形式と品質

  • html-to-imagetoPng()toJpeg()toSvg()toCanvas() を提供。JPEGでは品質調整可能。
// JPEGで品質80%
toJpeg(node, { quality: 0.8 });
  • html2canvas は常にCanvasを返すため、toDataURL('image/jpeg', 0.8) で形式と品質を指定。
html2canvas(node).then(canvas => {
  const dataUrl = canvas.toDataURL('image/jpeg', 0.8);
});

要素の除外や変更

html2canvasignoreElements オプションで特定の要素を除外できます。

html2canvas(node, {
  ignoreElements: (el) => el.classList.contains('no-screenshot')
});

html-to-imageskipFontscacheBust などの細かい制御が可能ですが、要素単位の除外はできません。代わりに、一時的にDOMを操作してからキャプチャする必要があります。

🚀 パフォーマンスと大規模DOM

  • 小〜中規模DOM(例:カード、チャート):html-to-image が高速で軽量。
  • 大規模DOM(例:長文ドキュメント、ダッシュボード):html2canvas がより安定。ただし、描画時間がかかる場合あり。

html2canvasscale オプションで解像度を調整でき、高DPIディスプレイ向けに高品質画像を生成可能です。

html2canvas(node, {
  scale: 2 // 通常の2倍の解像度
});

🔄 実際の開発シーンでの選定ガイド

ケース1:シンプルなUIカードをPNGで共有

  • 推奨: html-to-image
  • 理由: 軽量、CSS再現性が高い、APIが直感的
import { toPng } from 'html-to-image';

const download = async () => {
  const dataUrl = await toPng(document.getElementById('card'));
  const link = document.createElement('a');
  link.download = 'card.png';
  link.href = dataUrl;
  link.click();
};

ケース2:iframeを含むダッシュボード全体をキャプチャ

  • html-to-image はiframe非対応
  • 推奨: html2canvas(ただしiframe内は空白になる)
  • 注意: iframe内のコンテンツは別途キャプチャして合成する必要がある

ケース3:アニメーション中のCanvas要素を含むゲーム画面

  • ❌ いずれのライブラリも動的Canvasの内容を直接キャプチャできない
  • 対応策: Canvas自体を toDataURL() で取得し、別途合成

📌 まとめ:各ライブラリの特徴

特徴dom-to-imagehtml-to-imagehtml2canvas
メンテナンス状況非推奨アクティブアクティブ
内部実装SVG → CanvasSVG → CanvasCanvas再現
Webフォント対応△(手動対応必要)◯(自動埋め込み)△(CORS必須)
iframe対応△(空白になる)
複雑CSS対応△(SVG互換のみ)△(SVG互換のみ)✕(多くのプロパティ未対応)
大規模DOM
軽量さ△(やや重め)

💡 最終的なアドバイス

  • 新規プロジェクトでは、まず html-to-image を試してください。シンプルで再現性が高く、TypeScript対応も万全です。
  • 複雑なレイアウトや大量のDOM要素がある場合は、html2canvas の挙動を検証しましょう。特に、CSSの制限を事前に把握することが重要です。
  • dom-to-image は絶対に新規で使わないでください。既存コードがある場合も、可能なら html-to-image への移行を検討しましょう。

どのライブラリを選ぶにせよ、実際のターゲット環境(ブラウザ、OS、DPR)で必ずテストすることを忘れないでください。画像の再現性は環境によって大きく変わるためです。

選び方: dom-to-image vs html-to-image vs html2canvas

  • dom-to-image:

    dom-to-image はシンプルなDOM要素の画像化に適していますが、公式には非推奨(deprecated)とされています。新しいプロジェクトでは使用せず、代わりに後継である html-to-image を検討してください。既存プロジェクトで安定稼働している場合は、移行コストを考慮しつつ保守運用を続ける選択肢もありますが、新規開発では避けるべきです。

  • html-to-image:

    html-to-imagedom-to-image の後継として開発されており、同じSVGベースのアプローチを維持しながら、TypeScriptサポートやモダンなビルド環境、バグ修正を提供しています。CSSスタイルやWebフォントの再現性が高く、軽量で使いやすいAPIを求める場合に最適です。ただし、iframeや動的なCanvas要素など、高度なレンダリングには対応していません。

  • html2canvas:

    html2canvas はCanvas APIを用いてDOMを描画するため、iframeや動的コンテンツ、複雑なレイアウトを含むページでも比較的高い忠実度でスクリーンショットを取得できます。ただし、CSSの一部(例:mix-blend-modeclip-path)や外部フォントの読み込みに制限があり、結果がブラウザネイティブのスクリーンショットと異なる場合があります。大規模なDOMやアニメーション付き要素のキャプチャが必要な場合に有力な選択肢です。

dom-to-image のREADME

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