2021年4月20日火曜日

html-to-image で HTML を画像化する

HTML を JavaScript で画像にしたいニーズはそれなりにあります。 スクリーンショットを取りたいとか、案外使います。 そのような時に、これまで html2canvas というライブラリが非常に有名で、私も使っていました。

しかし html2canvas は正直に言って「非常に難しい」アプローチで実装されてるライブラリです。 言ってしまえば HTML/CSS の機能を完全にエミュレートしながら canvas に描画しているようなものです。 仮に一瞬完璧なものができたとしても、メンテが地獄であることは間違いありません。 正直、キツイと思う。 そんな中、ふと html-to-image という神ライブラリを見つけてしまいました。 html-to-image は、 dom-to-image という古のライブラリをメンテしやすく実装し直したライブラリです。

html-to-image は非常に頭の良い HTML の画像化をしています。 具体的には、画像化したい DOM を clone して、SVG の <foreignObject> として読み込みます。 SVG を画像化する API はブラウザに整っているので、特に複雑な処理をするまでもなく、toDataURL() で画像化できるという仕組みです。 考慮するべきは、Web フォントや HTML 内の画像くらいで、html2canvas のような超絶技巧は必要としません。 コードをチラ見してみても、非常にシンプルなコードで記載されていることがわかります。

そんなに簡単な方法があるのになぜ今まで採用されなかったかと言えば、Safari で <foreignObject> がセキュリティ的に動かなかったためのようです。 しかし、dom-to-image の issue を見ていると Safari 12 で動くようになったとのことです。 また私も iPhone Safari で確認してみたのですが、きちんと動いています。 ………つまり、始まったな? と考えて良いのではないでしょうか。

早速適当にページを作って変換してみたところ、ほぼ完璧に画像化できています。 ほんの少し変換が完璧でないところがある気がする (例えば <progress>) のですが、実用上は問題を感じることは少なそうで、かなり期待できそうな状態です。 駄目なケースとかまだよくわかってないのですが、あまりにも簡単な方法で画像化を実現できるので、html2canvas より安定するのではないかという期待もあります。 ライブラリ自体の進化は、dom-to-image の更新が停止しているので、 html-to-image のほうを見ていけば良さそう。

実装例

html-to-image はビルドが必要なので、 dom-to-image の実装例を残しておきます。使い方はほとんど一緒。以下のようにシンプルです。
var input = document.getElementById('dom-to-image-in');
var output = document.getElementById('dom-to-image-out');
domtoimage.toPng(input).then(function (dataUrl) {
  var img = new Image();
  img.src = dataUrl;
  output.appendChild(img);
}).catch(function (error) {
  console.error('oops, something went wrong!', error);
});

0 件のコメント: